WebSocket连接失败:WebSocket握手期间出错:发送了非空的'Sec-WebSocket-Protocol'头。

3

我正在使用ActionCable在Rails API / React项目中设置聊天功能,并试图找到最佳解决方案以进行连接身份验证。

该项目使用devise-jwt gem,因此我的授权是作为标头传递的。由于Web Sockets不允许头部,因此我一直在寻找最佳替代方案。我找到的解决方案建议采用以下方法之一(具有各种注意事项):

  • 将JWT作为查询参数发送到url中
  • 劫持HTTP_SEC_WEBSOCKET_PROTOCOL并通过这种方式发送

这两种解决方案都不太好,但我尝试使用第二个解决方案,因为在url中发送敏感信息(即使是编码后的JWT)感觉不太妥当。

这是我的connection.rb代码:

module ApplicationCable
  class Connection < ActionCable::Connection::Base
    identified_by :current_user

    def connect
      self.current_user = find_verified_user
    end

    private

    def find_verified_user
      begin
        jwt = request.env['HTTP_SEC_WEBSOCKET_PROTOCOL']
        decoded_jwt = JWT.decode(jwt, Rails.application.credentials.devise_jwt_secret_key)[0]
        id = decoded_jwt['sub']

        case decoded_jwt['scp']
        when 'admin'
          Admin.where(id: id).first
        when 'hero'
          Hero.where(id: id).first
        when'villain'
          Villain.where(id: id).first
        else
          reject_unauthorized_connection
        end
      rescue
        reject_unauthorized_connection
      end
    end
  end
end


我有三个不同的用户模型:管理员,(我们称之为)英雄和反派,因为某些原因。
现在,我的实际问题是:在服务器上,我可以获取JWT,解码它并找到我的管理员,但是在chrome控制台中,当我尝试创建套接字时,会出现以下错误:WebSocket connection to 'ws://localhost:3000/cable' failed: Error during WebSocket handshake: Sent non-empty 'Sec-WebSocket-Protocol' header but no response was received 这是对在chrome控制台中运行以下代码的响应:
token = "jwt.etc.blah..."
socket = new WebSocket(url, [token]);

服务器本身似乎没有问题:
Started GET "/cable" for ::1 at 2020-07-22 18:26:02 +0100
Started GET "/cable/" [WebSocket] for ::1 at 2020-07-22 18:26:02 +0100
Successfully upgraded to WebSocket (REQUEST_METHOD: GET, HTTP_CONNECTION: Upgrade, HTTP_UPGRADE: websocket)
Finished "/cable/" [WebSocket] for ::1 at 2020-07-22 18:26:02 +0100
  Admin Load (0.2ms)  SELECT "admins".* FROM "admins" WHERE "admins"."id" = $1 ORDER BY "admins"."id" ASC LIMIT $2  [["id", 1], ["LIMIT", 1]]
  ↳ app/channels/application_cable/connection.rb:19:in `find_verified_user'
Registered connection (Z2lkOi8vYXBpNTUtbWFpcy9BZG1pbi8x)

错误提示似乎在告诉我,我需要一些有关额外协议的确认或信息,这些协议是我已经将JWT hackily混入其中的...但我不知道如何去做。
任何帮助都将不胜感激!使用rails ActionCable是否可以发送附加协议?还是我必须使用查询参数?还是有更简洁的方法来解决这个问题?
这是我第一次尝试使用Web Sockets,所以提前感谢您的帮助!
1个回答

0
通过Sec-WebSocket-Protocol传递凭据是在基于Web的应用程序中进行WebSocket身份验证的常见解决方法,因为浏览器在连接初始化时不支持发送自定义标头。
如果您通过Sec-WebSocket-Protocol标头传递值,则服务器必须将相同的标头/值对返回给客户端。
由于Sec-WebSocket-Protocol标头不用于向WebSocket服务器传递凭据,因此您必须按照其规则操作,并将其视为协议并满足其要求。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接