这可能是基于意见的,但我仍然怀疑是否有最好的做法,因为我对websocket
做法几乎一无所知
我有一个从我自己的OP
获取JWT令牌的SPA。然后,它使用该JWT连接到我使用REST和WebSockets的其他服务。
就REST而言,它非常简单:
Authorization: Bearer ...
中发送)并提供对受保护资源的访问权限或使用401
进行响应,让SPA知道它需要请求新令牌。现在使用websockets:
在加载SPA期间,一旦我获得了令牌,我就会在我的网络服务中打开WS。我发送的第一条消息是带有JWT的login_message
,然后我会在服务器的websocket实例上知道谁发送消息。
我收到的每条后续消息都会验证JWT是否已过期。
据我所知,一旦它过期,我将面临两个选择:
删除某个类型的token_expired
错误的websocket,并在令牌刷新后强制浏览器建立新的websocket连接。
保持websocket打开,返回错误消息并发送新的登录消息(刷新令牌后)
不要使用登录信息,只需在每个请求中发送JWT。
问题:您会推荐哪种方法?为什么?在安全性和性能方面。还有其他我没有列出的常见做法吗?
答案 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"]);
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服务器仅接收文本:
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.');
});
});
已经分析了前面的主题,将新的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);
});
如果您需要此主题以外的内容,请告诉我。
答案 1 :(得分:0)
我问了一个很老的问题,所以我很乐意分享我们选择的做法:
客户端第一次获得JWT
时(应用程序启动时),将打开WebSocket。
为验证通道,我们发送了一条消息,我们将其定义为协议的一部分,称为authMessage
,其中包含该JWT
。
服务器将此数据存储在套接字的实例上,并在通过有线发送数据或从客户端接收数据之前验证其有效性/有效期。
令牌在过期之前会在Web应用程序中默默地刷新,并向服务器发布另一个authMessage
(从第2步重复)。
如果由于某种原因它在更新之前已过期,则服务器将关闭该套接字。
这大致就是我们在应用程序中实现的(没有优化),并且对我们来说真的很好。