基于 Swoole 开发实时在线聊天室(十七):Websocket 通信用户认证逻辑优化
实现方案
之前我们在 Websocket 通信中,用户认证实现非常粗暴,就是每次从请求字段获取 api_token
,然后在服务端判断对应用户记录是否存在:
if (!empty($data['api_token']) && ($user = User::where('api_token', $data['api_token'])->first())) {
...
}
我们可以这样来优化这个认证流程:
- 在升级到 Websocket 通信的 HTTP 路由中应用 Laravel 认证中间件,确保用户登录后才能建立 Websocket 连接;
- 然后在建立 Websocket 连接时,通过
$websocket->loginUsing()
方法设置此连接上的用户 ID,绑定用户认证状态; - 在具体发送消息的 Websocket 中,通过
$websocket->getUserId()
方法获取此连接上的认证用户 ID; - 最后,可以在断开 Websocket 连接时,通过
$websocket->logout()
方法取消用户认证状态绑定。
显然,这里我们结合了 hhxsv5/laravel-s 和 swooletw/laravel-swoole 两个扩展包的实现逻辑来优化 Websocket 通信中用户认证的自动化。
接下来我们来看看具体怎么做。
代码调整
首先让 socket.io
相关路由经过 Laravel 认证中间件 auth:api
过滤,非认证用户不能访问,这可以在 SocketIOController
控制器的构造函数中实现:
public function __construct()
{
$this->middleware('auth:api');
}
然后调整对应中间件代码(位于 app/Http/Middleware/Authenticate.php
),对未认证用户抛出认证异常警告,而不是跳转到 login
路由:
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
throw new AuthorizationException("登录后才能建立 Websocket 连接");
}
}
接下来,我们来到前端,Socket.io 客户端建立连接时需要指定 api_token
请求字段,以便服务端可以读取并进行自动认证,修改 socket.js
代码如下:
...
import store from "./store";
let api_token = store.state.userInfo.token;
const socket = io('http://webchats.test?api_token=' + api_token);
...
最后,打开 routes/websocket.php
,调整用户认证相关代码如下:
WebsocketProxy::on('connect', function (WebSocket $websocket, Request $request) {
// 发送欢迎信息
$websocket->setSender($request->fd);
// 建立连接时绑定认证用户信息
$websocket->loginUsing(auth('api')->user());
});
WebsocketProxy::on('room', function (WebSocket $websocket, $data) {
if ($userId = $websocket->getUserId()) {
$user = User::find($userId);
...
} else {
$websocket->emit('login', '登录后才能进入聊天室');
}
});
WebsocketProxy::on('message', function (WebSocket $websocket, $data) {
if ($userId = $websocket->getUserId()) {
$user = User::find($userId);
...
} else {
$websocket->emit('login', '登录后才能进入聊天室');
}
});
...
WebsocketProxy::on('disconnect', function (WebSocket $websocket, $data) {
roomout($websocket, $data);
$websocket->logout();
});
...
这里由于 Websocket
默认只提供了 getUserId
方法,没有提供 getUser
方法,所以还要经过再次查询获取认证用户详细信息,你也可以根据底层 loginUsingUserId
和 getUserId
的实现自行编写 loginUsingUser
和 getUser
的实现逻辑,这里就不再详细展开,另外,由于用户认证之后才能建立 Websocket 连接,所以 websocket.php
的 login
实现似乎也需要进行重构,感兴趣的同学可以自行去思考并实现,学院君这里就当是抛砖引玉,提供一下大体的思路和方案,更多细节留待你们自己去探究。
小结
关于 Swoole 入门到实战就简单介绍到这里,接下来,学院君将会继续 Laravel 从入门到精通教程的编写,以及把更多精力放到 Golang 的使用和推广上,PHP fpm 框架当然首推 Laravel,至于后续规模上来要进行微服务重构,推荐使用 Golang(Java 党可以绕过)。
4 条评论
完结撒花,学院君辛苦了
可以下载源码么
可以 源码在这里:https://github.com/nonfu/webchat
感谢