不幸的是,大多数websocket客户端和服务器都不支持附加额外的头信息和自定义头信息1。因此,可能的选择是:
path.to.api/cable?token=1234
request.params[:token]
缺点: 如果JWT被记录在日志和系统进程信息中,则可能会存在漏洞,供其他具有服务器访问权限的人使用,更多信息请参见 这里
解决方案: 对令牌进行加密并附加,即使在日志中可以看到它,也没有任何作用,除非其解密。
客户端:
# Append jwt to protocols
new WebSocket(url, existing_protocols.concat(jwt))
我创建了一个名为action-cable-react-jwt的JS库,适用于React
和React-Native
,它可以轻松完成此任务。随意使用。
服务器端:
def find_verified_user
begin
header_array = self.request.headers[:HTTP_SEC_WEBSOCKET_PROTOCOL].split(',')
token = header_array[header_array.length-1]
decoded_token = JWT.decode token, Rails.application.secrets.secret_key_base, true, { :algorithm => 'HS256' }
if (current_user = User.find((decoded_token[0])['sub']))
current_user
else
reject_unauthorized_connection
end
rescue
reject_unauthorized_connection
end
end
1 大多数Websocket API(包括Mozilla的)都像下面这个例子一样:
WebSocket构造函数接受一个必需参数和一个可选参数:
WebSocket WebSocket(
in DOMString url,
in optional DOMString protocols
);
WebSocket WebSocket(
in DOMString url,
in optional DOMString[] protocols
);
url
连接的URL;这应该是WebSocket服务器将响应的URL。
protocols
可选
一个协议字符串或协议字符串数组。这些字符串用于指示子协议,以便单个服务器可以实现多个WebSocket子协议(例如,您可能希望一个服务器能够处理根据指定的协议类型不同类型的交互)。如果您没有指定协议字符串,则假定为空字符串。
2 总有例外,例如这个node.js库ws允许构建自定义标题,因此您可以使用常规的Authorization: Bearer token
标题,并在服务器上解析它,但客户端和服务器都应使用ws
。