lemontreeshy 2019-07-12
上篇关于websocket的文章,登录确认session是通过与springsecurity结合,其登录后默认的session实现了principle,自动就能转换为websocketsession。
而当前的需求是自己实现的简单登录创建的httpsession怎么转换到websocketsession。
跟着下面的例子模拟体验
登录的时候,创建session 并存用户唯一标识
HttpSession httpsession = request.getSession(); httpsession.setAttribute("userName",username);
通过修改websocketconfig,最终将当前登录连接的websocket调整成跟用户名相关的连接。
//SessionAuthHandshakeInterceptor 定制的是simpSessionAttributes //setHandshakeHandler 定制的是simpUser registry.addEndpoint("/im-websocket").setAllowedOrigins("*").addInterceptors(new SessionAuthHandshakeInterceptor()) .setHandshakeHandler(new DefaultHandshakeHandler(){ @Override protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) { String userName= (String)attributes.get("userName"); UserPrincipal userPrincipal=new UserPrincipal(userName); return userPrincipal; } }) .withSockJS(); 其中SessionAuthHandshakeInterceptor核心代码,其将session的username转存到websocketsession的参数里。由上面的determineUser转为实现了Principal的用户类里。 public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) throws Exception { HttpSession session = getSession(request); if(session == null ){ return false; } attributes.put("userName",session.getAttribute("userName").toString()); return true; }
以下演示以两个用户分别连接、订阅用户列表公共通道,订阅私聊通道,发送单条信息为例
连接成功sessionid:333qmepi 地址:ws://localhost:8080/cepm/im-websocket/232/333qmepi/websocket 连接成功:王朝 登录服务 : GenericMessage [payload=byte[0], headers={simpMessageType=CONNECT, stompCommand=CONNECT, nativeHeaders={accept-version=[1.1,1.0], heart-beat=[10000,10000]}, simpSessionAttributes={userName=王朝}, simpHeartbeat=[J@39c5387a, simpUser=com.haiyisoft.cepm.config.websoket.UserPrincipal@d071c92, simpSessionId=333qmepi}] 登录服务结束: GenericMessage [payload=byte[0], headers={simpMessageType=CONNECT_ACK, simpConnectMessage=GenericMessage [payload=byte[0], headers={spanTraceId=83fe33462c0494b6, spanId=83fe33462c0494b6, simpMessageType=CONNECT, stompCommand=CONNECT, nativeHeaders={accept-version=[1.1,1.0], heart-beat=[10000,10000]}, simpSessionAttributes={userName=王朝}, simpHeartbeat=[J@39c5387a, messageSent=true, simpUser=com.haiyisoft.cepm.config.websoket.UserPrincipal@d071c92, spanSampled=0, simpSessionId=333qmepi}], simpUser=com.haiyisoft.cepm.config.websoket.UserPrincipal@d071c92, simpSessionId=333qmepi}] 订阅 : GenericMessage [payload=byte[0], headers={simpMessageType=SUBSCRIBE, stompCommand=SUBSCRIBE, nativeHeaders={id=[sub-0], destination=[/user/topic/private]}, simpSessionAttributes={userName=王朝}, simpHeartbeat=[J@6ed3203d, simpSubscriptionId=sub-0, simpUser=com.haiyisoft.cepm.config.websoket.UserPrincipal@d071c92, simpSessionId=333qmepi, simpDestination=/user/topic/private}] 订阅 : GenericMessage [payload=byte[0], headers={simpMessageType=SUBSCRIBE, stompCommand=SUBSCRIBE, nativeHeaders={id=[sub-1], destination=[/topic/userlist]}, simpSessionAttributes={userName=王朝}, simpHeartbeat=[J@7c7dec8a, simpSubscriptionId=sub-1, simpUser=com.haiyisoft.cepm.config.websoket.UserPrincipal@d071c92, simpSessionId=333qmepi, simpDestination=/topic/userlist}]
第二个人登录并订阅
影响第一个人的公共订阅回复: GenericMessage [payload=byte[47], headers={simpMessageType=MESSAGE, simpSubscriptionId=sub-1, contentType=application/json;charset=UTF-8, simpSessionId=333qmepi, simpDestination=/topic/userlist}] 连接成功sessionid:1nk35gag ws://localhost:8080/cepm/im-websocket/540/1nk35gag/websocket 连接成功:马汉 登录服务 : GenericMessage [payload=byte[0], headers={simpMessageType=CONNECT, stompCommand=CONNECT, nativeHeaders={accept-version=[1.1,1.0], heart-beat=[10000,10000]}, simpSessionAttributes={userName=马汉}, simpHeartbeat=[J@4023e40c, simpUser=com.haiyisoft.cepm.config.websoket.UserPrincipal@46d667d0, simpSessionId=1nk35gag}] 登录服务结束 : GenericMessage [payload=byte[0], headers={simpMessageType=CONNECT_ACK, simpConnectMessage=GenericMessage [payload=byte[0], headers={spanTraceId=4ccc5821d1d65934, spanId=4ccc5821d1d65934, simpMessageType=CONNECT, stompCommand=CONNECT, nativeHeaders={accept-version=[1.1,1.0], heart-beat=[10000,10000]}, simpSessionAttributes={userName=马汉}, simpHeartbeat=[J@4023e40c, messageSent=true, simpUser=com.haiyisoft.cepm.config.websoket.UserPrincipal@46d667d0, spanSampled=0, simpSessionId=1nk35gag}], simpUser=com.haiyisoft.cepm.config.websoket.UserPrincipal@46d667d0, simpSessionId=1nk35gag}] 订阅 : GenericMessage [payload=byte[0], headers={simpMessageType=SUBSCRIBE, stompCommand=SUBSCRIBE, nativeHeaders={id=[sub-0], destination=[/user/topic/private]}, simpSessionAttributes={userName=马汉}, simpHeartbeat=[J@19c4bde5, simpSubscriptionId=sub-0, simpUser=com.haiyisoft.cepm.config.websoket.UserPrincipal@46d667d0, simpSessionId=1nk35gag, simpDestination=/user/topic/private}] 订阅 : GenericMessage [payload=byte[0], headers={simpMessageType=SUBSCRIBE, stompCommand=SUBSCRIBE, nativeHeaders={id=[sub-1], destination=[/topic/userlist]}, simpSessionAttributes={userName=马汉}, simpHeartbeat=[J@34a6e51a, simpSubscriptionId=sub-1, simpUser=com.haiyisoft.cepm.config.websoket.UserPrincipal@46d667d0, simpSessionId=1nk35gag, simpDestination=/topic/userlist}]
第一个给第二个发私信
第一个人发送开启 : GenericMessage [payload=byte[82], headers={simpMessageType=MESSAGE, stompCommand=SEND, nativeHeaders={destination=[/app/private], content-length=[82]}, simpSessionAttributes={userName=王朝}, simpHeartbeat=[J@f3b84e7, simpUser=com.haiyisoft.cepm.config.websoket.UserPrincipal@d071c92, simpSessionId=333qmepi, simpDestination=/app/private}] 发送结束: GenericMessage [payload=byte[94], headers={simpMessageType=MESSAGE, nativeHeaders={simpOrigDestination=[/user/topic/private]}, simpSubscriptionId=sub-0, contentType=application/json;charset=UTF-8, simpSessionId=1nk35gag, simpDestination=/topic/private-user1nk35gag}]
可以看出来给哪个人发消息,谁能收到,就是跟simpUser这个值有关,如果里面的username和发送的时候写的一致,则他就可以接收到。
template.convertAndSendToUser(“接收人username”,"/topic/private",message)
第一段截取的代码不是最全,请知晓。
另外websocket在springboot1.5的自带tomcat下有问题,换成undertow
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-websocket</artifactId> <exclusions> <exclusion> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-tomcat</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-undertow</artifactId> </dependency>