什么';为WebSocket连接续订令牌是最佳做法

什么';为WebSocket连接续订令牌是最佳做法,websocket,jwt,openid-connect,Websocket,Jwt,Openid Connect,这可能是基于观点的,但我仍然想知道有没有最佳实践,因为我对websocket实践几乎一无所知 我有一个SPA,可以从我自己的OP获得JWT令牌。然后,它使用该JWT连接到我使用REST和WebSocket拥有的其他服务 就休息而言,它非常简单: REST API验证JWT(在授权:承载…中发送),并提供对受保护资源的访问,或使用401响应,让SPA知道它需要请求新令牌 现在使用WebSocket: 在SPA加载过程中,一旦我得到一个令牌,我就会打开一个Web服务的WS。我发送的第一条消息是带

这可能是基于观点的,但我仍然想知道有没有最佳实践,因为我对
websocket
实践几乎一无所知

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

就休息而言,它非常简单:

  • REST API验证JWT(在
    授权:承载…
    中发送),并提供对受保护资源的访问,或使用
    401
    响应,让SPA知道它需要请求新令牌
现在使用WebSocket:

在SPA加载过程中,一旦我得到一个令牌,我就会打开一个Web服务的WS。我发送的第一条消息是带有JWT的
login\u消息
,然后我将其保存在服务器的websocket实例中,以了解谁在发送消息。 我收到的每个后续消息都会验证JWT,看它是否过期

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

  • 删除带有某种类型的
    令牌\u过期的
    错误的websocket,并在刷新令牌后强制浏览器建立新的websocket连接

  • 保持websocket打开,返回错误消息并发送新的登录消息(一旦令牌刷新)

  • 不要使用登录消息,只需在每个请求中发送JWT


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

    Oauth2 flow有两个选项来续订令牌。正如您在上所说,这些选项中的一个选项是向用户提示一条消息,以强制执行新的登录过程

    另一个选项是使用刷新\u令牌,在该选项中,每次会话到期时,您都将避免向用户进行此登录过程,并以静默方式续订令牌

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

    正如我们所看到的,jwt再生是按照oauth2规范解决的,并且是在客户端执行的,在您的例子中是SPA

    因此,下一个问题是:如何将这个jwt(新的或更新的)传递给外部资源(经典的RESTAPI或您的websocket)

    经典Rest Api

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

    Websocket

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

    此外,没有标题的概念,因此您需要使用以下方式将此信息(在您的案例中为jwt)发送到websocket:

    • 协议
    • 饼干
    • 简单获取参数
    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);
    });
    
    未涵盖的主题
    • 如何使用刷新令牌执行jwt重新生成
    • 如何处理无声再生

    如果您需要这些未涵盖的主题,请告诉我。

    我问了一个很老的问题,因此我很乐意与您分享我们选择的做法:

  • 一旦客户机第一次获得他的
    JWT
    (当应用程序启动时),就会打开一个WebSocket

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

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

  • 令牌在web应用程序过期前几分钟内以静默方式刷新,并向服务器发出另一条
    authMessage
    (从步骤2开始重复)

  • 如果由于任何原因,它在更新之前过期,服务器将关闭该套接字


  • 这大致就是我们在应用程序中实现的(没有优化),对我们来说效果非常好。

    #1您所说的“OP”是什么意思#2经典方法是将用户/密码交换为新的jwt。那么,我发送的第一条消息是什么意思呢?我的JWT
    OP
    和OpenID Provider一样是一条登录消息。当时,我们试图通过JWT为WebSocket应用身份验证,而不干扰用户输入其凭据,方法是在服务器端实现,或者删除WebSocket并使用刷新的JWT重新授权。我将在一两天内详细介绍我们提出的实践,因为我看到了大家对这个问题的兴趣。使用REST时,一切都很简单,WS保持套接字打开,因此需要解决令牌过期而套接字仍然打开的情况。基本流程是什么#1个用户进入acme.com,输入其凭据,生成jwt令牌以能够使用您的任何API,如果令牌过期,则使用websockets生成新令牌?或者#2 acme.com没有登录表单,用户进入acme.com,使用某些逻辑,该用户使用WebSocket获取jwt令牌,如果jwt过期,则使用WebSocket生成新令牌。。。。。。。。。。
    var ws = new WebSocket("ws://example.com/service?key1=value1&key2=value2");
    
    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.');
        });
    });
    
    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);
    });