【问题标题】:Javascript websocket client library which can pass custom headers in handshake request可以在握手请求中传递自定义标头的 Javascript websocket 客户端库
【发布时间】:2016-11-29 23:42:54
【问题描述】:

我需要一个 javascript 库来连接到我的 web-socket 服务器,该服务器是使用 python twisted 实现的。我尝试了 Native javascript web-socket 客户端,但它没有传递自定义标头 as per this link 的选项。我的 web-socket 服务器通过从握手标头中获取 auth_token 来进行身份验证,就像 Oauth2 标准一样。是否有任何可用于 web-socket 客户端的 javascript 库允许在连接时传递自定义标头?

【问题讨论】:

    标签: javascript websocket


    【解决方案1】:

    很抱歉成为坏消息的承担者...但是 - 正如the question 中提到的那样,您正在引用并且您可以从the standard Websocket API 中学习(这不是外部库,它就是使用浏览器)...您不能为 websocket 连接设置自定义标头。

    WebSocket(url,protocols) 构造函数接受一两个参数。第一个参数 url 指定要连接的 URL。第二个,protocols,如果存在的话,要么是一个字符串,要么是一个字符串数组。 ...数组中的每个字符串都是一个子协议名称。只有当服务器报告它选择了这些子协议之一时,才会建立连接。 ...

    但是,一切都没有丢失。

    由于这是您的 websocket 服务器,您可以选择:

    1. 我很确定 OAuth2 使用令牌作为 GET 或 POST 请求的参数,而不是作为自定义标头。这意味着(也许)您可以将令牌作为连接字符串的一部分传递,即:

       websocket = new WebSocket('wss://my.server.com/?access_token=secret_acess_token');
      

      像这样传递会话令牌可能并不理想,并且可能会带来安全风险...所以我会在这里选择第二个选项:

    2. 新的 websocket 连接(除非我的浏览器是特殊的)使用与建立主连接相同的 cookie 启动 - 这意味着 websocket 层可以访问来自 Http 层的所有 cookie 和会话数据......

      因此,可以设置一个唯一的 cookie - 或者,甚至更好(假设您的 http 和 websocket 共享相同的代码库并且可以很好地协同工作),在服务器端会话存储中设置一个身份验证令牌 - 并使用该数据验证连接或拒绝连接。

    由于我不是 Python 专家,这里有一个使用 Ruby 的Plezi framework(我是作者)的快速演示:

    require 'plezi'
    
    class DemoCtrl
       # this is the Http index page response
       def index
          response.write "#{cookies[:notice]}\n\n" if cookies[:notice] && (cookies[:notice] = nil).nil?
          #returning a string automatically appends it to the response.
          "We have cookies where we can place data:\n#{request.cookies.to_s}\n"
       end
       # the login page
       def login
          cookies[:my_token] = "a secret token"
          cookies[:notice] = "logged in"
          redirect_to :index
       end
       # the logout page
       def logout
          cookies[:my_token] = nil
          cookies[:notice] = "logged out"
          redirect_to :index
       end
       # a Plezi callback, called before a websocket connection is accepted.
       # it's  great place for authentication.
       def pre_connect
          puts "Websocket connections gave us cookies where we can place data:\n#{request.cookies.to_s}\n"
          return false unless cookies.to_s[:my_token] == "a secret token"
          # returning true allows the connection to be established
          true
       end
       def on_message data
          puts "echoing #{data}"
          response << "echo: #{data}"
       end
    end
    
    # setup the route to our demo
    Plezi.route '/', DemoCtrl
    # Plezi will start once the script is finished.
    # if you are running this in irb, use:
    exit
    

    访问:http://loaclhost:3000/

    要尝试启动 websocket,请打开 web 检查器并在控制台中运行以下脚本:

    ws = new WebSocket("ws://localhost:3000/"); ws.onopen = function(e) { console.log("open"); }; ws.onmessage = function(e) { console.log(e.data);};
    
    ws.send("Go Bears");
    

    这应该失败,因为我们还没有进行身份验证...

    访问http://loaclhost:3000/login,然后重试。

    现在应该可以了。

    如果您愿意,请尝试http://loaclhost:3000/logout

    【讨论】:

    • 感谢 Myst 的回复。现在我用解决方法来解决这个问题。只是使用规定通过多个子协议来传递 auth_token。如果在 header 中找不到令牌,服务器将检查传递的子协议。
    猜你喜欢
    • 1970-01-01
    • 2019-01-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-08-23
    • 1970-01-01
    • 2015-09-08
    相关资源
    最近更新 更多