是否可以对 websocket 升级请求使用不记名身份验证?
Posted
技术标签:
【中文标题】是否可以对 websocket 升级请求使用不记名身份验证?【英文标题】:Is it possible to use bearer authentication for websocket upgrade requests? 【发布时间】:2014-04-18 10:49:22 【问题描述】:打开 websocket 连接的升级请求是标准的 HTTP 请求。在服务器端,我可以像其他任何请求一样验证请求。就我而言,我想使用承载身份验证。不幸的是,在浏览器中打开 websocket 连接时无法指定标头,这会让我相信不可能使用承载身份验证来验证 web socket 升级请求。所以——我错过了什么,还是真的不可能?如果不可能,这是设计使然,还是 Websocket API 的浏览器实现中的公然疏忽?
【问题讨论】:
【参考方案1】:API 允许您只设置一个标头,即 Sec-WebSocket-Protocol,即应用程序特定的子协议。您可以使用此标头来传递不记名令牌。例如:
new WebSocket("ws://www.example.com/socketserver", ["access_token", "3gn11Ft0Me8lkqqW2/5uFQ="]);
服务器应接受其中一种协议,因此对于上面的示例,您只需验证令牌并使用标头 Sec-WebSocket-Protocol=access_token 进行响应。
【讨论】:
我使用了这种方法,除了我将令牌和值连接到一个“协议”值中。谢谢! 你有使用Authorization
header 代替Sec-WebSocket-Protocol
header 的解决方案吗?
不,但如果客户端是 JS,服务器可能更容易读取 access_token 作为不记名令牌(是的,非常愚蠢)。
我想这取决于您的观点,无论是功能还是黑客,但它是作为 应用程序特定 子协议的,因此应用程序可以请求和使用标头但是它喜欢。
是的,这仍然是最好的方法。鉴于这是在规范中,它不会很快改变,而且我不知道有任何标准化努力允许从 js 对 websocket 请求标头进行一般访问。此外,要回复@jayongg,可以设置 cookie,它们会与 ws 升级请求一起发送。【参考方案2】:
你是对的,由于javascript WebSocket API的设计,现在不可能使用Authentication header。 更多信息可以在这个线程中找到: HTTP headers in Websockets client API
但是,Bearer 身份验证类型允许一个名为“access_token”的请求参数:http://self-issued.info/docs/draft-ietf-oauth-v2-bearer.html#query-param 该方法兼容websocket连接。
【讨论】:
文档告诉你它不安全,除非绝对必要,否则不要使用它。【参考方案3】:在 websocket 连接之前使用令牌 servlet http 请求标头进行基本身份验证的示例:
****ws://localhost:8081/remoteservice/id?access_token=tokenValue****
验证您的令牌,如果有效则返回 true,否则返回 false
端点配置:
@Configuration
@EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer
@Autowired
RemoteServiceHandler rsHandler;
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry)
registry.addHandler(rsHandler, "/remoteservice/vin").setAllowedOrigins("*").addInterceptors(new HttpHandshakeInterceptor());
在建立 websocket 连接之前验证令牌:
public class HttpHandshakeInterceptor implements HandshakeInterceptor
@Override
public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map attributes) throws Exception
ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) request;
String token = servletRequest.getServletRequest().getHeader("access_token");
try
Claims claims = Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
if (claims!=null)
return true;
catch (Exception e)
return false;
return false;
跳过http安全端点
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter
@Override
public void configure(WebSecurity web) throws Exception
web.ignoring().anyRequest();
pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt</artifactId>
<version>0.9.0</version>
</dependency>
在js文件中随意添加请求头
var request = URLRequest(url: URL(string: "ws://localhost:8081/remoteservice")!)
request.timeoutInterval = 5 // Sets the timeout for the connection
request.setValue("someother protocols", forHTTPHeaderField: "Sec-WebSocket-Protocol")
request.setValue("14", forHTTPHeaderField: "Sec-WebSocket-Version")
request.setValue("chat,superchat", forHTTPHeaderField: "Sec-WebSocket-Protocol")
request.setValue("Everything is Awesome!", forHTTPHeaderField: "My-Awesome-Header")
let socket = WebSocket(request: request)
【讨论】:
以上是关于是否可以对 websocket 升级请求使用不记名身份验证?的主要内容,如果未能解决你的问题,请参考以下文章
是否可以通过 webhook 发送不记名访问令牌?如果不是,我怎么能通过代码做到这一点?