SpringSecurity整合WebSocket并携带token

这篇具有很好参考价值的文章主要介绍了SpringSecurity整合WebSocket并携带token。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

目的

导入SpringSecurity的SpringBoot项目,在连接WebSocket时进行token校验

实现

SpringBoot整合Websocket的相关知识就不过多赘述,本文主要介绍WebSocket权限校验相关

1. 前端

WebSocket连接

 var windowTag = `${user.id}-${Math.random().toString(36).substr(2)}`;
 var token = user.token;

websocket = new WebSocket(`ws://localhost:9001/ws/chat/${windowTag}`,[token]);

windowTag是生成的随机窗口唯一标识符,token是用户登录后生成的令牌token
当前端发起WebSocket连接请求时,请求头在通信子协议Sec-WebSocket-Protocol里携带token
SpringSecurity整合WebSocket并携带token

2. 后端

前端通过WebSocket的通信子协议携带token发送给后端,现在我们只需要获取到该token就能获取用户信息

/**
  WebSocket配置
*/
@Configuration
public class WebSocketConfig extends ServerEndpointConfig.Configurator {

    @Bean
    public ServerEndpointExporter serverEndpointExporter(){
        return new ServerEndpointExporter();
    }

    /**
     * 建立握手时,连接前的操作
     */
    @Override
    public void modifyHandshake(ServerEndpointConfig sec, HandshakeRequest request, HandshakeResponse response) {
        // 这个userProperties 可以通过 session.getUserProperties()获取
        final Map<String, Object> userProperties = sec.getUserProperties();
        Map<String, List<String>> headers = request.getHeaders();
        List<String> protocol = headers.get(WEBSOCKET_PROTOCOL);
        // 存放自己想要的header信息
        if(protocol != null){
            userProperties.put(WEBSOCKET_PROTOCOL, protocol.get(0));
        }
    }

    /**
     * 初始化端点对象,也就是被@ServerEndpoint所标注的对象
     */
    @Override
    public <T> T getEndpointInstance(Class<T> clazz) throws InstantiationException {
        return super.getEndpointInstance(clazz);
    }

}

将请求头中Sec-WebSocket-Protocol携带的token放入session的userProperties中,方便连接时获取token

@Slf4j
@Component
@ServerEndpoint(value = "/ws/chat/{windowTag}",configurator = WebSocketConfig.class)
public class ChatEndPoint {

    //用线程安全的map来保存当前用户
    private static Map<String, ChatEndPoint> onlineUsers = new ConcurrentHashMap<>();
    //声明一个session对象,通过该对象可以发送消息给指定用户,不能设置为静态,每个ChatEndPoint有一个session才能区分.(websocket的session)
    private Session session;

    //建立连接
    @OnOpen
    public void onOpen(Session session, @PathParam("windowTag") String windowTag){
        this.session = session;
        String username = getUserName(session);
        log.info("上线用户名称: {}", username);
        onlineUsers.put(username + "-" + windowTag, this);
        log.info("在线用户数: {}", onlineUsers.size());
    }

	......

    // 获取用户名
    private String getUserName(Session session){
        String token = getHeader(session, WEBSOCKET_PROTOCOL);
        return new TokenManager().getUserInfoFromToken(token);
    }

	public String getHeader(Session session, String headerName) {
        String header = (String) session.getUserProperties().get(headerName);
        if (StringUtils.isBlank(header)) {
            try {
                session.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return header;
    }
}

通过子协议中携带的token获取用户名,并与窗口标识符拼接成连接标识符,之后将连接的session存放进线程安全的Map中

/**
	SpringSecurity的权限校验器
*/
public class TokenAuthFilter extends BasicAuthenticationFilter {

    private TokenManager tokenManager;

    public TokenAuthFilter(AuthenticationManager authenticationManager, TokenManager tokenManager) {
        super(authenticationManager);
        this.tokenManager = tokenManager;
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        System.out.println("根据token获取用户权限并放入security上下文...");
        // websocket需要验证Sec-WebSocket-Protocol中的token
        String token = request.getHeader(WEBSOCKET_PROTOCOL);
        if(token == null){
            token = request.getHeader("token");
        }
        //获取当前认证成功用户权限信息
        UsernamePasswordAuthenticationToken authRequest = getAuthentication(token);
        //判断如果有权限信息,放到权限上下文中
        if(authRequest != null) {
            SecurityContextHolder.getContext().setAuthentication(authRequest);
        }
        chain.doFilter(request,response);
    }

    private UsernamePasswordAuthenticationToken getAuthentication(String token) {
        System.out.println("请求头中的token: " + token);
        if(!token.equals("null")) {
            //从token获取用户名
            String username = tokenManager.getUserInfoFromToken(token);
            System.out.println("token获取用户名:"+username);
            //从token获取对应权限列表
            List<String> permissionValueList = tokenManager.getUserPermissionList(token);
            Collection<GrantedAuthority> authority = new ArrayList<>();
            if(permissionValueList != null){
                for(String permissionValue : permissionValueList) {
                    SimpleGrantedAuthority auth = new SimpleGrantedAuthority(permissionValue);
                    authority.add(auth);
                }
            }
            return new UsernamePasswordAuthenticationToken(username,token,authority);
        }
        return null;
    }
}

在SpringSecurity权限校验时先获取Sec-WebSocket-Protocol携带的token
当我们以为一切准备就绪时,运行时发现报错了
SpringSecurity整合WebSocket并携带token
WebSocket握手阶段出错:发送了非空“Sec-WebSocket-Protocol”请求头但是响应中没有此字段。在后端握手时设置一下请求头(Sec-WebSocket-Protocol)即可,前端发来什么值,这里就写什么值

@Order(1)
@Component
@WebFilter(filterName = "WebsocketFilter", urlPatterns = "/ws/**")
public class WebSocketFilter implements Filter {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        String token = ((HttpServletRequest) servletRequest).getHeader(WEBSOCKET_PROTOCOL);
        // 解决 Sent non-empty 'Sec-WebSocket-Protocol' header but no response was received
        response.setHeader(WEBSOCKET_PROTOCOL,token);

        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy() {}
}

连接成功!!
SpringSecurity整合WebSocket并携带token
SpringSecurity整合WebSocket并携带token
功能测试
SpringSecurity整合WebSocket并携带token文章来源地址https://www.toymoban.com/news/detail-443519.html

到了这里,关于SpringSecurity整合WebSocket并携带token的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Vue3---请求拦截器携带token

    为什么要在请求拦截器携带Token? Token作为用户标识,在很多个接口中都需要携带Token才可以正确获取数据,所以需要在接口调用时携带Token。另外,为了统一控制采取请求拦截器携带的方案 如何配置? Axios请求 拦截器 可以在接口正式发起之前对请求参数做一些事情,通常Toke

    2024年02月15日
    浏览(37)
  • 【SpringSecurity】十一、SpringSecurity集成JWT实现token的方法与校验

    添加JWT的maven依赖: application.yaml中配置密钥的值,方便代码中引用和后续更改: 这里的命名改为JWTService好点,Utils命名似乎偏静态方法一点。 再贴一下下统一结果类的定义: 下面是安全用户类,用于在数据库的用户对象类SysUser和返给框架的官方对象类UserDetails之间做过渡转

    2024年02月10日
    浏览(31)
  • HttpURLConnection中请求头中携带Token的使用方法

    一般会在头部添加认证信息,如token值或BasicAuth认证的 Authorization值

    2024年02月05日
    浏览(31)
  • 【Uniapp】小程序携带Token请求接口+无感知登录方案2.0

    本次改进原文《【Uniapp】小程序携带Token请求接口+无感知登录方案》,在实际使用过程中我发现以下 bug : 若token恰好在用户访问接口时到期,就会直接查询为空,不反映token过期问题(例如:弹窗显示订单查询记录为空),并不是因为没有数据而是因为token过期了,接口返回

    2024年02月09日
    浏览(28)
  • websocket如何携带header或参数

    一  websocket如何携带参数 相信用过websocket的同学都知道,直接在url后面拼接参数即可。不多做阐述。 二  websocket如何携带header 最近项目组接到新需求,需要websocket连接时,在header里面传递token,由于token较长,不适合在url中直接拼接。 网上查阅了相关的资料, websocket 没有像

    2024年01月23日
    浏览(29)
  • SpringSecurity实现前后端分离登录token认证详解

    目录 1. SpringSecurity概述 1.1 权限框架 1.1.1 Apache Shiro 1.1.2 SpringSecurity 1.1.3 权限框架的选择 1.2 授权和认证 1.3 SpringSecurity的功能 2.SpringSecurity 实战 2.1 引入SpringSecurity 2.2 认证 2.2.1 登录校验流程  2.2.2 SpringSecurity完整流程  2.2.3 认证流程详解 2.3 思路分析 2.4 代码实战 2.4.1  自定义

    2024年02月08日
    浏览(33)
  • SpringSecurity OAuth2 配置 token有效时长

    1.这种方式配置之后,并没有生效 2.第二种方法时改数据库的配置,测试配置有效

    2024年02月09日
    浏览(35)
  • WebSocket的那些事(6- RabbitMQ STOMP目的地详解)

    在上节 WebSocket的那些事(5-Spring STOMP支持之连接外部消息代理)中我们已经简单介绍了各种目的地类型,如下图: 这一节我们来详细探讨一下各种目的地类型的区别。 在 MESSAGE 报文中请求头 destination 的格式如下: 发布到默认交换机的消息目的地格式为: /queue/queue_name 。 发

    2024年02月08日
    浏览(30)
  • WebSocket和SpringSecurity的学习记录

    1. WebSocket 基础概念 什么是 WebSocket? WebSocket 是一种网络通信协议,提供了在单个 TCP 连接上进行全双工通信的方式。\\\"全双工\\\"意味着客户端和服务器可以同时发送和接收信息,这与传统的 HTTP 请求不同,后者是一种半双工通信方式(即一次只能进行一个请求或响应)。 WebSock

    2024年01月21日
    浏览(24)
  • 【SpringCloud Gateway】SpringCloud各微服务之间用户登录信息共享的实现思路——gateway网关token校验以及向微服务发送请求携带token

            最近在学习SpringCloud项目时,想到了一些问题,各个微服务分别部署在不同的服务上,由naocs作为注册中心实现负载均衡,彼此之间通过Feign相互调用通信,信息同步并不像单体项目那样方便,传统单体项目的登录验证方式似乎在SpringCloud中不能满足项目的需求。那么

    2024年02月05日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包