2016-09-25 28 views
4

我的角2个应用程序(编码的打字稿)有一个简单的身份验证方案:在的WebSocket,角2和JSON网络令牌认证

  • 用户登录:
  • 服务器返回JSON网络令牌(JWT)abc123...
  • 在每个API调用,应用程序发送的智威汤逊在Authorization
  • Server验证的智威汤逊和赠款访问

现在我想添加websockets。我想知道如何在那里验证用户。由于我不控制哪些头被发送到websocket服务器(WS),所以我无法发送JWT。

我的想法至今(尚未实施):

  • 客户端打开的WebSocket:let sock = new WebSocket('wss://example.com/channel/');
  • WS服务器接受没有任何身份验证检查握手。标准HTTP标头在此阶段可用。
  • 客户端收听套接字上的open事件。一旦插座被打开:
    • 客户端发送的消息与type='auth'
    • payload='JWT_VALUE'
  • WS服务器期望的插座上第一消息是auth类型。一旦被接收,服务器读取有效载荷,验证JWT_VALUE并且设置isAuthenticated标志
    • 如果验证失败,服务器断开插座
    • 如果没有isAuthenticated客户端发送的任何其他类型的消息,服务器断开插座

2个问题:服务器资源,可以采取由谁连接,但从来没有发JWT的客户,以及更简洁的方案会阻止握手如果客户端未通过身份验证。

其他的想法:

  • 客户端可以在路径发送JWT:new WebSocket('wss://example.com/channel/<JWT>/')
    • 亲:此信息握手期间可
    • CON:路径似乎并没有成为适合JWT的地方。特别是因为中间代理和访问日志将保存路径;当设计的HTTP API我已经做出了决定,不包括智威汤逊在url
  • 服务器可以读取客户端的IP +用户代理和对阵这是由HTTP服务器创建的JWT发出时,数据库记录。然后服务器会猜测谁是连接
    • 亲:握手(不知道IP)
    • 骗子在这个信息可能是可用的:它似乎可怕的不安全为“猜测”一个客户端应关联一个JWT,当时客户从来没有把它展示出来。例如,假冒受害者的UA并使用相同网络(代理服务器,公共WiFi,大学内联网......)的人将能够冒充受害者。

请问你的WebSockets验证客户端?假设用户已经通过HTTP登录,并且Angular 2应用程序有一个JWT令牌。

+0

我实际上实现了你的第一个想法 - 在握手后的第一条消息中发送JWT令牌。这不是一个非常干净的解决方案,但它的工作原理。 – Rem

回答

3

我定居在以下方案:

1.客户端登录到该网站并接收和认证令牌(JSON网络令牌)

GET /auth 
{ 
    user: 'maggie', 
    pwd: 'secret' 
} 

// response 
{ token: '4ad42f...' } 

2.验证的客户端请求的WebSocket连接票

GET /ws_ticket 
Authorization: Bearer 4ad42f... 

// response: single-use ticket (will only pass validation once) 
{ ticket: 'd76a55...', expires: 1475406042 } 

3.客户端打开网页套接字,在查询参数发送票

var socket = new WebSocket('wss://example.com/channel/?ticket=d76a55...'); 

4. WebSocket伺服器(PHP),然后接受握手

/** 
* Receives the URL used to connect to websocket. Return true to admit user, 
* false to reject the connection 
*/ 
function acceptConnection($url){ 
    $params = parse_str(parse_url($url, PHP_URL_QUERY)); 
    return validateTicket($params['ticket']); 
} 

/** Returns true if ticket is valid, never-used, and not expired. */ 
function validateTicket($ticket){/*...*/} 
+0

感谢您分享您的解决方案。我正在寻找实施类似的东西;即通过查询字符串参数传递认证信息。为什么选择在#2中创建一次性令牌(票证),而不是直接传递JWT?看起来你的WSS URL是安全的,所以通过JWT可能是一个更简单的选择,不是吗? – BillyBBone

+0

@BillyBBone正如我在OP中提到的那样,我在设计HTTP API时已经决定让JWT避开URL。具体来说,我不希望这些令牌在服务器日志中显示(甚至是我自己的日志) – BeetleJuice

0

客户端打开之前验证票websocket,发送用户名和密码查询参数

ws://<username>:<password>@<ip-address><path> 

例如:new $ WebSocket('ws:// user:[email protected]/util')

+1

这很有趣;我没有想到这一点,我喜欢简单但我有一些担心。网络流量日志不会存储这些信息吗?此外,这需要用户输入她的用户名和密码来打开一个websocket(因为websockets在后台打开而不是很好的体验)或者应用程序将用户名和密码缓存在本地存储中(我不想这样做) – BeetleJuice