[英]WeBSocket Authentication in Spring using spring security
According to official spring documentation:根据官方 spring 文档:
WebSockets reuse the same authentication information that is found in the HTTP request when the WebSocket connection was made.
当建立 WebSocket 连接时,WebSockets 重用在 HTTP 请求中找到的相同身份验证信息。 This means that the Principal on the HttpServletRequest will be handed off to WebSockets.
这意味着 HttpServletRequest 上的 Principal 将被移交给 WebSockets。 If you are using Spring Security, the Principal on the HttpServletRequest is overridden automatically.
如果您使用的是 Spring 安全性,则 HttpServletRequest 上的 Principal 将被自动覆盖。
More concretely, to ensure a user has authenticated to your WebSocket application, all that is necessary is to ensure that you setup Spring Security to authenticate your HTTP based web application.
More concretely, to ensure a user has authenticated to your WebSocket application, all that is necessary is to ensure that you setup Spring Security to authenticate your HTTP based web application.
If I understood it correctly, this means that WebSocket is using the same channel for communication since the handshake, and thus the authentication should be made on the first connection.如果我理解正确,这意味着 WebSocket 自握手以来使用相同的通信通道,因此应在第一次连接时进行身份验证。
However nowhere is stated how to actually authenticate the handshake in a standard secure way.然而,没有说明如何以标准的安全方式实际验证握手。 As far as I am aware HTTP doesn't send an Authentication header while upgrading to the WebSockets so how it is done?
据我所知 HTTP 在升级到 WebSockets 时不会发送身份验证 header 那么它是如何完成的?
Do I really need to send authentication token in connection query, eg我真的需要在连接查询中发送身份验证令牌吗,例如
localhost:8080/ws?Auth=...
and leave the security to HTTPS并将安全性留给 HTTPS
Or do I need to authenticate the WebSocket after the connection is made eg create my own handshake?或者我是否需要在建立连接后验证 WebSocket,例如创建我自己的握手?
Is there any proper formal way to do it?有没有适当的正式方式来做到这一点? I am using RAW websockets.
我正在使用 RAW websockets。
Thanks for the ideas/help.感谢您的想法/帮助。
I personally use STOMP but with STOMP (basically a framework for communications on raw WebSocks), the session cookie (from spring security) is send with any message down the socket.我个人使用 STOMP,但使用 STOMP(基本上是原始 WebSocks 上的通信框架),session cookie(来自 spring 安全性)与任何消息一起通过套接字发送。
You can use the StompAccessorHeader
like:您可以像使用
StompAccessorHeader
一样:
@MessageMapping("/agents/start")
public void start(StompHeaderAccessor stompHeaderAccessor) {
log.info("Subscriber Start! {}-{}", stompHeaderAccessor.getUser() != null ? stompHeaderAccessor.getUser().getName() : "ANON", stompHeaderAccessor.getSessionId());
mysessionstore.addSessionId(stompHeaderAccessor.getSessionId());
}
With not using the STOMP framework there may be a way to read the SessionCookie sent per request on the raw socket?如果不使用 STOMP 框架,可能有一种方法可以读取原始套接字上每个请求发送的 SessionCookie?
I am not 100% sure but I am guessing you are using the TextWebSocketHandler
implmentation with the:我不是 100% 确定,但我猜你正在使用
TextWebSocketHandler
实现:
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage textMessage)
I can see in the source code for WebSocketSession you should be able to get your principal authenticate user there:我可以在 WebSocketSession 的源代码中看到您应该能够在那里获得您的主要身份验证用户:
https://github.com/spring-projects/spring-framework/blob/0de2833894c24c1e70bde991bad171435c6ecac2/spring-websocket/src/main/java/org/springframework/web/socket/WebSocketSession.java#L37 https://github.com/spring-projects/spring-framework/blob/0de2833894c24c1e70bde991bad171435c6ecac2/spring-websocket/src/main/java/org/springframework/web/socket/WebSocketSession.java#L37
So you authenticate like normal REST like POST "/login" and then that session should be valid for the websockets as well.所以你像普通的 REST 一样进行身份验证,比如 POST "/login" 然后 session 也应该对 websockets 有效。
You may be able to auth via the socket?您可以通过套接字进行身份验证吗? You'd have to like make your own socket endpoint to take their credentials and do
SecurityContextHolder.getContext().setAuthentication(myAuthUserToken)
but maybe that will then pass a session cookie back?您必须创建自己的套接字端点来获取他们的凭据并执行
SecurityContextHolder.getContext().setAuthentication(myAuthUserToken)
但也许这会传递一个 session cookie 回来? You'd have to test this ofc as I am unsure if it would work shrug .你必须测试这个 ofc,因为我不确定它是否会起作用shrug 。
I personally then make a "store" (a singleton or redis) that holds the user principal and the socketSessionId so I can then match a user to a socket.然后我个人创建了一个“存储”(singleton 或 redis)来保存用户主体和 socketSessionId,这样我就可以将用户与套接字匹配。
You could say store them in a singleton with a HashMap<String,String> userPrincipalNameToSocketSessionId
as a crude way store which socket session belongs to which user.您可以说将它们存储在 singleton 中,并使用
HashMap<String,String> userPrincipalNameToSocketSessionId
作为粗略的方式存储套接字 session 属于哪个用户。
eg.例如。
A bit like有一点像
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage textMessage){
MySessionStore.addSessionToMap(session.getPrincipal(),session.getId());
log.info("Added user {} websocket session {} to the store.",session.getPrincipal(),session.getId());
}
public */MySingletonClass*/ MySessionStore{
@Getter
public static volatile HashMap<String,String> userPrinciapalToSocketMap = new HashMap<>();
//Method to add to map here
public synchronized static addToMap(String principalName,String webSocketSessionId){
...Adds to the map.
}
JWT Stateless Auth System wanting a Socket Session? JWT 无状态身份验证系统想要一个套接字 Session?
As far as I can guess with this one...unless there is a lot of overriding and practically forking/extending lots of Spring classes...据我所知,这...
You could make a controller:您可以制作 controller:
Http GET => "/websocket-ticket"
which would return a signed token with the user's principal/username/id for the UX to then pass as a first message after websocket connect. Http GET => "/websocket-ticket"
这将返回一个带有用户主体/用户名/id 的签名令牌,然后在 websocket 连接后作为第一条消息传递。
The socket handler TextMessageHandler
can check the signaute of the token and add it to your HashMap<String,String> principalUserToSessionId
store.套接字处理程序
TextMessageHandler
可以检查令牌的签名并将其添加到您的HashMap<String,String> principalUserToSessionId
存储中。
The security issue (unlikely but it is there):安全问题(不太可能但确实存在):
An attacker with XSS could snoop that token and hijack that websocket session.具有 XSS 的攻击者可以窥探该令牌并劫持该 websocket session。 Maybe you win on a race condition (ie the MITM takes longer and the token is single use...more wonderful implementation...you now also need a "websocket-ticket-consumed" store...).
也许您在竞争条件下获胜(即 MITM 需要更长的时间,并且令牌是一次性使用的......更精彩的实现......你现在还需要一个“websocket-ticket-consumed”商店......)。
https://devcenter.heroku.com/articles/websocket-security https://devcenter.heroku.com/articles/websocket-security
I am feeling this is all heading to the X/Y problem.我觉得这一切都在走向 X/Y 问题。 Why are you using JWTs for Auth?
为什么要使用 JWT 进行身份验证?
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.