更新WebSocket连接令牌的最佳做法是什么

时间:2017-01-08 15:24:12

标签: websocket jwt openid-connect

这可能是基于意见的,但我仍然怀疑是否有最好的做法,因为我对websocket做法几乎一无所知

我有一个从我自己的OP获取JWT令牌的SPA。然后,它使用该JWT连接到我使用REST和WebSockets的其他服务。

就REST而言,它非常简单:

  • REST API验证JWT(在Authorization: Bearer ...中发送)并提供对受保护资源的访问权限或使用401进行响应,让SPA知道它需要请求新令牌。

现在使用websockets:

在加载SPA期间,一旦我获得了令牌,我就会在我的网络服务中打开WS。我发送的第一条消息是带有JWT的login_message,然后我会在服务器的websocket实例上知道谁发送消息。 我收到的每条后续消息都会验证JWT是否已过期。

据我所知,一旦它过期,我将面临两个选择:

  1. 删除某个类型的token_expired错误的websocket,并在令牌刷新后强制浏览器建立新的websocket连接。

  2. 保持websocket打开,返回错误消息并发送新的登录消息(刷新​​令牌后)

  3. 不要使用登录信息,只需在每个请求中发送JWT。

  4. 问题:您会推荐哪种方法?为什么?在安全性和性能方面。还有其他我没有列出的常见做法吗?

2 个答案:

答案 0 :(得分:1)

Oauth2流具有两个更新令牌的选项。正如您在这些选项中所述,系统会提示您一条消息,以强制执行新的登录过程。

另一种选择是使用 refresh_token ,在这种情况下,每次会话到期时,您都将避免向用户登录该过程,并以静默方式续订令牌。

在这两种情况下,都需要将jwt存储在客户端中(通常在登录后)并进行更新(在交互式登录或静默再生之后)。本地存储,存储或只是一个简单的全局变量是处理存储和更新客户端中的jwt的替代方法。

我们可以看到,jwt再生是根据oauth2规范解决的,并在您的情况下在客户端SPA执行。

所以下一个问题是:如何将这个jwt(新的或续订的)传递给外部资源(经典的REST API或您的websocket)?

经典休息Api

在这种情况下,您可能知道,使用http标头发送jwt很容易。在每个http调用中,我们都可以将旧的/有效的jwt或更新的jwt发送为标头,通常为Authorization: Bearer ...

Websocket

在这种情况下,这并不是一件容易的事,因为根据快速回顾,没有明确的方法可以在建立连接后更新标题或任何其他“元数据”

此外,没有标头的概念,因此您需要使用以下方法将此信息(在您的情况下为jwt)发送到Websocket:

  • 协议
var ws = new WebSocket("ws://example.com/path", ["protocol1", "protocol2"]);
  • cookies
document.cookie = 'MyJwt=' + jwt + ';'
var ws = new WebSocket(
    'wss://localhost:9000/wss/'
);
  • 简单的获取参数
var ws = new WebSocket("ws://example.com/service?key1=value1&key2=value2");

Websocket仅接收文本

根据以下链接,websocket可以在稳定阶段提取标头,获取参数和协议:

之后,websocket服务器仅接收文本:

const http = require('http');
const WebSocketServer = require('websocket').server;
const server = http.createServer();
server.listen(9898);
const wsServer = new WebSocketServer({
    httpServer: server
});
wsServer.on('request', function(request) {
    const connection = request.accept(null, request.origin);
    connection.on('message', function(message) {
      //I can receive just text 
      console.log('Received Message:', message.utf8Data);
      connection.sendUTF('Hi this is WebSocket server!');
    });
    connection.on('close', function(reasonCode, description) {
        console.log('Client has disconnected.');
    });
});

在每个请求中发送jwt

已经分析了前面的主题,将新的o更新令牌发送到您的websocker后端的唯一方法是在每个请求中发送它:

const ws = new WebSocket('ws://localhost:3210', ['json', 'xml']);
ws.addEventListener('open', () => {
  const data = {
         jwt: '2994630d-0620-47fe-8720-7287036926cd',
         message: 'Hello from the client!' 
     }
  const json = JSON.stringify(data);
  ws.send(json);
});

未涵盖的主题

  • 如何使用refresh_token执行jwt再生
  • 如何处理无声再生

如果您需要此主题以外的内容,请告诉我。

答案 1 :(得分:0)

我问了一个很老的问题,所以我很乐意分享我们选择的做法:

  1. 客户端第一次获得JWT时(应用程序启动时),将打开WebSocket。

  2. 为验证通道,我们发送了一条消息,我们将其定义为协议的一部分,称为authMessage,其中包含该JWT

  3. 服务器将此数据存储在套接字的实例上,并在通过有线发送数据或从客户端接收数据之前验证其有效性/有效期。

  4. 令牌在过期之前会在Web应用程序中默默地刷新,并向服务器发布另一个authMessage(从第2步重复)。

  5. 如果由于某种原因它在更新之前已过期,则服务器将关闭该套接字。

这大致就是我们在应用程序中实现的(没有优化),并且对我们来说真的很好。