小码哥
发布于

基于Token认证的WebSocket连接

概要

WebSocket 作为一种支持浏览器与服务器全双工通信的协议,对于复杂的前端应用,在交互体验和性能的改进上,是一种非常合适的解决方案。随着 WebSocket 更多地应用于生产开发,安全也成为了必须要关注的问题。

关于安全有一个可能的误区是:如果用户通过了 Web 应用的认证(登录了系统),建立的 WebSocket 连接,就也是经过认证的。实际上,这是两个完全不同的通道,socket 连接需要建立自己的认证体系。

认证的方式(cookie or Token)

有两种方式可以解决认证的问题,一种是传统的基于 cookie,一种是基于 Token 的。

两种方式比较起来,个人更倾向于基于 Token 的方案。主要是以下几方面考虑:

  • 耦合性。基于 cookie,意味着,应用本身的认证和提供 WebSocket 的服务,得是同一套 session cookie 的管理机制。有的时候,可能这也不是大的问题,但是以目前我们工程中的大部分场景看,应用服务是基于 Java 的一些 Web framework,而 socket 由 Socket.IO 来提供。让两个功能的系统协调一种共享的认证方式,就不那么容易。所以,需要解除这种对应用服务的依赖。
  • session 的管理。同时,如果 WebSocket 服务自己来维护基于 cookie 的认证,就需要借助一些存储(DB、Redis)来存储 session。作为一个纯为解决通信连接的服务,这一块也是不希望来维护的。
  • 适用性。另外,cookie 也会在有些设备或浏览器设置中被禁用,在这种情况下,就还需要一种替代的方式来实现认证。这一点上,cookie 也是不如基于 Token 的。

基于 Token 的认证

在 Token 的实现方式上,可以选择 JSON Web Token(JWT)。这是一种开放的轻量级的认证规范(RFC 7519),用于保证在用户和服务器之间传递安全可靠的信息。

以下是一个简单的例子,基于 express、Socket.IO 来构建了一个支持认证的 WebScoket 通信服务。

其中,用到了两个实现库:

服务端

应用服务模块,在用户登录的时候创建一个 token,

var jwt = require('jsonwebtoken');

app.post('/login', function (req, res) {

  var profile = {
    name: 'david',
    email: 'david@alibaba.com',
    id: 123
  };

  // 根据profile信息生产token
  var token = jwt.sign(profile, jwtSecret);

  res.json({token: token});
});

var server = http.createServer(app);

在 Socket.IO 模块,绑定一个全局的回调用来做认证。

var socketioJwt = require('socketio-jwt');

var sio = socketIo.listen(server);

sio.set('authorization', socketioJwt.authorize({
  secret: jwtSecret,
  handshake: true
}));

sio.sockets
  .on('connection', function (socket) {
     console.log('connected');
     //socket.on('event');
  });

server.listen(9000, function () {
  console.log('listening on http://localhost:9001');
});

其中,jwtSecret 需要保存在服务器上,用来完成 JWT 的验证。

如果客户单发送了有效的 JWT,相当于握手成功并且 connection 就会建立。

客户端

以下是一个简单的客户端例子:

function connect_socket (token) {
  var socket = io.connect('', {
    query: 'token=' + token
  });

  socket.on('connect', function () {
    console.log('authenticated');
  }).on('disconnect', function () {
    console.log('disconnected');
  });
}

$('#login').submit(function (e) {
  e.preventDefault();
  $.post('/login', {
    username: $('username').val(),
    password: $('password').val()
  }).done(function (result) {
    connect_socket(result.token);
  });
});

相比较基于 cookie,基于 token 的方式非常易于代码实现,且便于集成到已有系统中。

评论(6)
小码哥
小码哥

反作弊刻不容缓啊

点赞
评论
sbzedrh
sbzedrh

最近冒出的英文帖有点担心老哥站

点赞
评论
Akira
Akira

这个是在首页列表页面,不是详情页面哦

点赞
评论
Akira
Akira

edge 浏览器,win10 系统下,这个应该是广告显示导致的,广告把内容挤压到右侧,广告没有显示出来,就成了这个结果

点赞
评论
小码哥
小码哥

为啥我这里的页面没啥问题呢,奇怪了哦。我截个图你看下。。。

image.png

点赞
评论
Akira
Akira

页面乱了 2222.png

点赞
评论