Spring WebSocket 应用,鉴权token,多个页面访问同一个websocket

目录

1、SpringBoot+WebSocket没有token鉴权

2、WebSocket通过url鉴权token (postman可测试成功)

3、WebSocket通过 自定义协议 "sec-websocket-protocol"鉴权

        

         4、解决困扰我很久的问题


本人是看过这些博客后,在实际应用中总结出来的,遇到的问题也很多,但是站在巨人的肩膀上就是会少走弯路!!!感谢!!

spring boot 集成 websocket 的四种方式 - 简书

实战 | spring boot 集成 websocket 的四种方式_mb6140060e201b0的技术博客_51CTO博客

WebSocket实现鉴权方案__alone_的博客-CSDN博客_websocket 鉴权

cookie、token与xss、csrf攻击 - 下一秒钟已经不同 - 博客园

1、SpringBoot+WebSocket没有token鉴权

原生注解部分

①、pom文件——注入websocket依赖;

②、websocketConfig配置文件——添加ServerEndpointExporter配置bean

③、接收连接的类WebSocketServer——加上@ServerEndpoint注解用来配置ws访问的地址信息,并实现onOpen、onClose、onMessage、onError等方法;

这里的CopyOnWriteArraySet<WebSocketServer>

concurrent包的线程安全Set,用来存放每个客户端对应的MyWebSocket对象。这里不管用户开了几个页面来与websocket接口建立连接,存进set的都是不同的session,互相不会影响。

另外看过很多博客说加了@ServerEndpoint加了注解后,同时连接多个页面的时候有冲突,,靠加注解@Scope("prototype") 单例变多例来解决,这样不一定能解决问题,我建议大家有时间还是先分析自己的程序。像set<对象>的时候就不会出现这种情况(毕竟每次存进set中的对象是不同的)。

④、基类——包括返回给前端的各种数据;

⑤、service层——写三个图对应的业务逻辑代码;

⑥、TimeTask——实现定时任务,浏览器与服务器建立连接后,后端定时向前端sendMessage。

2、WebSocket通过url鉴权token (postman可测试成功)

Spring封装

① pom文件——注入websocket依赖;

② config配置类——通过向 WebSocketHandlerRegistry 设置不同参数来进行配置。其中 addHandler 方法添加我们上面的写的 ws 的 handler 处理类,第二个参数是你暴露出的 ws 路径。addInterceptors 添加我们写的握手过滤器。setAllowedOrigins("*") 这个是关闭跨域校验,方便本地调试,线上推荐打开。

③ interceptor拦截器——HandshakeInterceptor 接口来定义握手拦截器,这里是建立握手时的事件,分为握手前与握手后

④ Manager业务类——这里简单通过 ConcurrentHashMap 来实现了一个 session 池,用来保存已经登录的 web socket 的 session。服务端发送消息给客户端必须要通过这个 session。

这个地方要注意的!!!一个用户token下 多个页面访问同一个websocket的情况

这里的map应该存的是token鉴权 Map<token,session>,若是同一个用户同时连接多个websocket接口 ,那么每个接口的token和session都会进入这个map,又因为同一个用户的token是相同的,那么map的hash值相同的情况下,只有最后一组接口才能进入map ,也就是说只有最后一个websocket接口能成功连接。

这里的解决办法是①前端改成一个大的接口包含所有数据结果,然后监听返回给多个小接口,测试可行;②后端将map中的session,改为List<session>。我看过很多博客说加注解@Scope("prototype") 单例变多例的情况,亲测没用。

主要是interceptor程序中,握手前在获取token的时候从parameter获取,postman的测试结果也在下图

// 通过URL获得请求参数
ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest) request;
Object token = serverHttpRequest.getServletRequest().getParameter("token");

众所周知,放参数在url上,多少沾点不安全,比如 xss csrf 攻击。

xss:用户通过各种方式将恶意代码注入到其他用户的页面中。就可以通过脚本获取信息,发起请求,之类的操作。

csrf:跨站请求攻击,简单地说,是攻击者通过一些技术手段欺骗用户的浏览器去访问一个自己曾经认证过的网站并运行一些操作(如发邮件,发消息,甚至财产操作如转账和购买商品)。由于浏览器曾经认证过,所以被访问的网站会认为是真正的用户操作而去运行。这利用了web中用户身份验证的一个漏洞:简单的身份验证只能保证请求发自某个用户的浏览器,却不能保证请求本身是用户自愿发出的。csrf并不能够拿到用户的任何信息,它只是欺骗用户浏览器,让其以用户的名义进行操作。

3、WebSocket通过 自定义协议 "sec-websocket-protocol"鉴权

大部分程序还是基于第二步 Spring 封装

主要是interceptor程序中,握手前,采用自定义协议header获得token

String token = serverHttpRequest.getServletRequest().getHeader("Sec-WebSocket-Protocol");

重点来了!!!这里写完handler类中的建立连接方法 afterConnectionEstablished 确实会走,这里给人造成一种连接成功的假象,其实会立马跳到断开连接方法 afterConnectionClosed,并告诉你failed。解决办法来了!!!

在服务端接受方式(WebSocketInterceptor中 beforeHandshake方法中)加上这行代码

serverHttpResponse.getServletResponse().setHeader("Sec-WebSocket-Protocol", authorization);

public boolean beforeHandshake(ServerHttpRequest request, ServerHttpResponse response, WebSocketHandler wsHandler, Map<String, Object> attributes) {
        ServletServerHttpRequest serverHttpRequest = (ServletServerHttpRequest) request;
        ServletServerHttpResponse serverHttpResponse = (ServletServerHttpResponse) response;
        String authorization = serverHttpRequest.getServletRequest().getHeader("Sec-WebSocket-Protocol");
        //这里对获取到的 authorization 授权码进行业务校验如 jwt 校验
        //...
        //在后端握手时设置一下请求头(Sec-WebSocket-Protocol),前端发来什么授权值,这里就设置什么值,不设置会报错导致建立连接成功后立即被关闭
        serverHttpResponse.getServletResponse().setHeader("Sec-WebSocket-Protocol", authorization);
        log.info("start shaking hands->>>");
        return true;
    }

浏览器测试的失败和成功页面。

绝了!!!

4、解决困扰我很久的问题

1:建立连接成功后立即被关闭;

2:一个用户token下 多个页面访问同一个websocket不成功的

  • 3
    点赞
  • 38
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
Spring Cloud中,可以使用Spring Security框架来实现Token的认证和授权,同时也可以使用WebSocket来实现实时通信功能。下面介绍如何在Spring Cloud中使用WebSocket来监听Token过期: 1. 配置WebSocketSpring Cloud项目中,需要配置WebSocket以支持实时通信功能。在配置类上加上@EnableWebSocket注解,然后注册一个WebSocketHandler,用于处理WebSocket连接和消息。 ```java @Configuration @EnableWebSocket public class WebSocketConfig implements WebSocketConfigurer { @Override public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) { registry.addHandler(myHandler(), "/myHandler").setAllowedOrigins("*"); } @Bean public WebSocketHandler myHandler() { return new MyHandler(); } } ``` 2. 获取TokenWebSocket的处理器中,可以使用Spring Security提供的SecurityContextHolder来获取当前用户的认证信息。从认证信息中可以获取到Token的信息,包括Token的过期时间。 ```java public class MyHandler extends TextWebSocketHandler { @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); String token = ((OAuth2Authentication) authentication).getOAuth2Request().getRequestParameters().get("access_token"); OAuth2AccessToken accessToken = tokenStore.readAccessToken(token); if (accessToken == null || accessToken.isExpired()) { // Token已过期,向前端发送一个消息 session.sendMessage(new TextMessage("Token已过期,请重新登录!")); } } } ``` 需要注意的是,这里的OAuth2Authentication和tokenStore需要根据具体的实现进行调整。 3. 实现Token过期监听 在WebSocket的处理器中,需要实现Token过期的监听功能。可以使用Spring Security提供的OAuth2AccessToken来判断Token是否过期,如果过期,则向前端发送一个消息。 ```java public class MyHandler extends TextWebSocketHandler { @Override public void afterConnectionEstablished(WebSocketSession session) throws Exception { Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); String token = ((OAuth2Authentication) authentication).getOAuth2Request().getRequestParameters().get("access_token"); OAuth2AccessToken accessToken = tokenStore.readAccessToken(token); if (accessToken == null || accessToken.isExpired()) { // Token已过期,向前端发送一个消息 session.sendMessage(new TextMessage("Token已过期,请重新登录!")); } } @Override public void handleTransportError(WebSocketSession session, Throwable exception) throws Exception { if (exception instanceof OAuth2AccessTokenExpiredException) { // Token已过期,向前端发送一个消息 session.sendMessage(new TextMessage("Token已过期,请重新登录!")); } else { super.handleTransportError(session, exception); } } } ``` 需要注意的是,这里的OAuth2AccessTokenExpiredException是Spring Security框架提供的异常类,用于表示Token已过期。当WebSocket连接出现异常时,可以通过捕获OAuth2AccessTokenExpiredException来判断Token是否过期。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值