繁体   English   中英

使用 spring 安全性在 Spring 中进行 WebSocket 身份验证

WeBSocket Authentication in Spring using spring security

提示:本站收集StackOverFlow近2千万问答,支持中英文搜索,鼠标放在语句上弹窗显示对应的参考中文或英文, 本站还提供   中文繁体   英文版本   中英对照 版本,有任何建议请联系yoyou2525@163.com。

根据官方春季文档:

WebSocket 重用在建立 WebSocket 连接时在 HTTP 请求中找到的相同身份验证信息。 这意味着 HttpServletRequest 上的 Principal 将移交给 WebSockets。 如果您使用的是 Spring Security,则 HttpServletRequest 上的 Principal 将被自动覆盖。

更具体地说,为了确保用户已通过您的 WebSocket 应用程序的身份验证,所有必要的是确保您设置 Spring Security 来验证您的基于 HTTP 的 Web 应用程序。

如果我理解正确,这意味着自握手以来 WebSocket 使用相同的通道进行通信,因此应该在第一次连接时进行身份验证。

然而,没有任何地方说明如何以标准的安全方式实际验证握手。 据我所知,HTTP 在升级到 WebSockets 时不会发送身份验证标头,那么它是如何完成的?

我真的需要在连接查询中发送身份验证令牌,例如

localhost:8080/ws?Auth=... 

并将安全性留给 HTTPS

或者我是否需要在建立连接后对 WebSocket 进行身份验证,例如创建我自己的握手?

有什么适当的正式方法可以做到吗? 我正在使用 RAW websockets。

感谢您的想法/帮助。

1 个回复

我个人使用 STOMP,但使用 STOMP(基本上是原始 WebSocks 上的通信框架),会话 cookie(来自 Spring Security)与任何消息一起通过套接字发送。

您可以使用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());
    }

如果不使用 STOMP 框架,可能有办法读取原始套接字上每个请求发送的 SessionCookie 吗?

我不是 100% 确定,但我猜你正在使用TextWebSocketHandler实现:

@Override
protected void handleTextMessage(WebSocketSession session, TextMessage textMessage)

我可以在 WebSocketSession 的源代码中看到您应该能够在那里获得您的主要身份验证用户:

https://github.com/spring-projects/spring-framework/blob/0de2833894c24c1e70bde991bad171435c6ecac2/spring-websocket/src/main/java/org/springframework/web/socket/WebSocketSession.java#L37

因此,您像 POST "/login" 这样的普通 REST 一样进行身份验证,然后该会话也应该对 websocket 有效。

您可以通过套接字进行身份验证吗? 您必须喜欢制作自己的套接字端点以获取他们的凭据并执行SecurityContextHolder.getContext().setAuthentication(myAuthUserToken)但也许这会传回会话 cookie? 你必须测试这个 ofc,因为我不确定它是否可以耸肩

然后我个人创建了一个“存储”(单例或 redis)来保存用户主体和 socketSessionId,这样我就可以将用户与套接字进行匹配。

您可以说使用HashMap<String,String> userPrincipalNameToSocketSessionId将它们存储在单例中,作为存储哪个套接字会话属于哪个用户的粗略方式。

例如。

有点像

@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 无状态身份验证系统需要套接字会话?

据我猜测,除非有很多覆盖和实际上分叉/扩展很多 Spring 类...

你可以做一个控制器:

Http GET => "/websocket-ticket"它将返回一个带有用户主体/用户名/id 的签名令牌,用于 UX,然后在 websocket 连接后作为第一条消息传递。

套接字处理程序TextMessageHandler可以检查令牌的签名并将其添加到您的HashMap<String,String> principalUserToSessionId存储中。

安全问题(不太可能,但确实存在):

使用 XSS 的攻击者可以窥探该令牌并劫持该 websocket 会话。 也许你在竞争条件下获胜(即 MITM 需要更长的时间并且令牌是一次性的......更精彩的实现......你现在还需要一个“websocket-ticket-consumed”商店......)。

https://devcenter.heroku.com/articles/websocket-security

我觉得这一切都指向 X/Y 问题。 为什么要使用 JWT 进行身份验证?

1 具有Spring安全性的Websocket身份验证

我正在Tomcat7上使用Spring MVC构建一个webapp,我正在使用Spring Security进行用户身份验证。 除了标准控制器,我还有一个websocket servlet需要连接进行身份验证。 流程如下:客户端连接到服务器并重定向到登录页面,成功验证后,他收到的视图尝试 ...

3 使用角色的 Spring 安全性 - api 身份验证

我的认证班 这是我的身份验证类,当我尝试访问它时,我希望它询问 /daily 和 /quarterly 的用户名和密码。 此外,每个人都应该有权访问“/”网址。 但是,现在,如果我先调用“/quarterly”,那么它会要求进行身份验证,而不是“/daily”。 所以无论我先打电话给谁,都会被要求进 ...

8 如何在Java中使用身份验证令牌进行Spring安全性

我正在用Spring 4构建一个应用程序,并在Java中使用其余的Web服务。因此,对于所有Web服务,我想发送用户名,带有URL的密码以保护Web服务。用户名应为“ ADMIN”,密码应为“ ADMIN123”。点击服务后,它应该发送一个身份验证令牌,该值我可以用于该会话。 服务等级 ...

9 Spring安全性:使用http basic和表单登录进行身份验证

我有一个巨大而奇怪的身份验证问题。 我有两种类型的身份验证,一种是通过网页运行,一种是我的网络服务,它不起作用。 事实上,即使我不提供凭据,服务器也会接受我的身份验证并继续执行。 这是一个很大的问题,我不明白为什么,我想: 1)外部Web服务是/ client / * URL,必须进 ...

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2022 STACKOOM.COM