首页 > 其他分享 >security整合websocket

security整合websocket

时间:2023-09-11 18:13:07浏览次数:42  
标签:websocket 整合 class token CSRF registration Override security public

快速使用

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketSecurityConfig
        extends AbstractSecurityWebSocketMessageBrokerConfigurer {
    @Autowired
    UserDetailsServiceImpl userDetailsService;

    @Autowired
    RedisTemplate<String,Object> redisTemplate;

    @Override
    public void registerStompEndpoints(StompEndpointRegistry registry) {
        registry.addEndpoint("/ws/chat").setAllowedOriginPatterns("*").withSockJS();
    }

    @Override
    public void configureMessageBroker(MessageBrokerRegistry registry) {
        registry.enableSimpleBroker("/queue");
    }
    @Override
    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
        messages.simpSubscribeDestMatchers("/queue").permitAll()
        .simpDestMatchers("/ws/chat").permitAll();
    }

    
    @Override
    protected boolean sameOriginDisabled() {
        return true; // 禁用 CSRF 验证
    }




}

一开始继承AbstractSecurityWebSocketMessageBrokerConfigurer类之后,发现无论如何都要经过CSRF拦截,建立连接总会被拦截。经过排查代码发现此类中重写的方法如下

@Override
public final void configureClientInboundChannel(ChannelRegistration registration) {
   ChannelSecurityInterceptor inboundChannelSecurity = this.context.getBean(ChannelSecurityInterceptor.class);
   registration.setInterceptors(this.context.getBean(SecurityContextChannelInterceptor.class));
    
   if (!sameOriginDisabled()) {
      registration.setInterceptors(this.context.getBean(CsrfChannelInterceptor.class));
   }
   if (this.inboundRegistry.containsMapping()) {
      registration.setInterceptors(inboundChannelSecurity);
   }
   customizeClientInboundChannel(registration);
}

发现sameOriginDisabled是默认写死

/**
 * <p>
 * Determines if a CSRF token is required for connecting. This protects against remote
 * sites from connecting to the application and being able to read/write data over the
 * connection. The default is false (the token is required).
 * </p>
 * <p>
 * Subclasses can override this method to disable CSRF protection
 * </p>
 * @return false if a CSRF token is required for connecting, else true
 */
/**
*该方法用于确定是否需要CSRF令牌进行连接。这样可以保护应用免受远程站点连接并能够通过连接读取/写入数据的攻击。默认值为false(需要令牌)。
*子类可以覆盖此方法以禁用CSRF保护。
*返回值:
*如果需要CSRF令牌进行连接,则返回false,否则返回true。
*/
protected boolean sameOriginDisabled() {
   return false;
}

所以要在子类中覆写这个方法 返回true,然后就绕过了同源策略

本人这里不懂为什么要继承这个类,网上搜是可以用来做身份默认校验,但是我如果用自定义的手段,这里的代码意义就不是很大了。比如我现在token是在请求头里传过来,然后要去redis里面去找。

@Configuration
@EnableWebSocketMessageBroker
public class WebScoketConfig implements WebSocketMessageBrokerConfigurer {
    @Autowired
    RedisTemplate<String,Object> redisTemplate;

    @Autowired
    UserDetailsServiceImpl userDetailsService;
    
    @Override
    public void configureClientInboundChannel(ChannelRegistration registration) {
        registration.interceptors(new ChannelInterceptor() {
            @Override
            public Message<?> preSend(Message<?> message, MessageChannel channel) {
                StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
                if(StompCommand.CONNECT.equals(accessor.getCommand())){
                    System.out.println("进行验证----------------------------------------");
                    String token = accessor.getFirstNativeHeader("Authorization");
                    if (StrUtil.isBlank(token)) {
                        throw new PasswordExpiredException("未携带token");
                    }
                    Authentication authentication = (Authentication) redisTemplate.opsForValue().get(RedisConstant.AUTHENTICATION_CACHE_KEY_PREFIX + token);
                    if (ObjectUtil.isEmpty(authentication))
                        throw new PasswordExpiredException("token错误或失效,请重新登录");

                    userDetailsService.loadUserByUsername(authentication.getName());
                    accessor.setUser(authentication);
                }
                return message;
            }
        });
    }
}

然后就可以开一个controller接口用来建立链接了

@Controller
public class UserChatController {

    @Autowired
    SimpMessagingTemplate messagingTemplate;

    Logger logger = LoggerFactory.getLogger(UserChatController.class);
    @MessageMapping("/ws/chat")
    @SendTo("/queue")
    public void handleChat(Authentication authentication, ChatMsg msg) {
        System.out.println("执行到这里");
        String name = authentication.getName();
        msg.setFrom(name);
        System.out.println(name);
        System.out.println(msg.getTo());
        messagingTemplate.convertAndSendToUser(msg.getTo(),"/queue/chat",msg);
    }
}

标签:websocket,整合,class,token,CSRF,registration,Override,security,public
From: https://www.cnblogs.com/letfly/p/17694155.html

相关文章

  • SpringBoot-Learning系列之Kafka整合
    SpringBoot-Learning系列之Kafka整合本系列是一个独立的SpringBoot学习系列,本着WhatWhyHow的思想去整合Java开发领域各种组件。消息系统主要应用场景流量消峰(秒杀抢购)、应用解耦(核心业务与非核心业务之间的解耦)异步处理、顺序处理实时数据传输管道异构语言架构......
  • [SpringSecurity5.6.2源码分析六]:ChannelProcessingFilter
    1、基础用法• ChannelProcessingFilter是SpringSecurity的第一个过滤器,具体排序规则见FilterComparator,image.png• 主要作用:可限制服务端接受的安全协议,比如说仅支持Https或者Http1.1开启配置类:• 首先我们注册到容器中的WebSecurityConfigurerAdapter是针对于WebSecurity的......
  • ClickHouse使用之二 ——整合mysql,实现数据库创建查询导出
    1.mysql创建一个用于clickhouse的账号mysql_clickhouse并且授权CREATEUSER'mysql_clickhouse'@'%'IDENTIFIEDBY'Password123!';GRANTALLPRIVILEGESON*.*TO‘mysql_clickhouse’@‘%';2. 使用mysql引擎创建一个clickhouse的外部表存在一个mysql的数据库:host:......
  • 基于Flask+websocket实现一个在线聊天室网站系统
    在今天的互联网时代,实时通信成为了许多应用和服务的核心特色。从社交媒体到在线游戏,无处不在的即时互动为用户带来了难以置信的沉浸体验。有了这种背景,为何不深入了解如何构建自己的实时聊天应用呢?在本文中,我们将介绍如何使用Flask和Websockets通过Flask-SocketIO框架创建一......
  • 【校招VIP】前端计算机网络之webSocket相关
    考点介绍WebSocket是一种网络通信协议,很多高级功能都需要它。初次接触WebSocket的人,都会问同样的问题:我们已经有了HTTP协议,为什么还需要另一个协议?它能带来什么好处?答案很简单,因为HTTP协议有一个缺陷:通信只能由客户端发起。答案详情解析和文章内容可点击下方链接即可查......
  • Jmeter获取Websocket多帧消息的实现方法
       由于需要对WebSocket进行压力测试,因此又回归到了JMeter的使用。网络上缺少具体的获取多帧消息的操作,且自己也踩了两个坑,总结一下可行的操作供大家参考。 一、情况说明    被测试的WebSocket会根据客户端发起的信息进行回复,回复帧数不确定。现在需要把所有回复......
  • 原生JavaScript框架设计(一):整合JS函数
    本篇为回顾js时总结,诣在整理JS中常用知识点,剖析其规律。模仿jQuery,简单一些,特定功能,像apply函数、getElementXXX函数等浏览器函数都没有实现,直接套用。创建common.js://自定义实现push函数varmyPush=function(target,els){ varj=target.length, i=0; while((target[j++]=e......
  • Redis缓存整合 考虑的一些方面(2)
    当与Redis缓存整合时,还可以考虑以下一些方面:缓存击穿处理:当某个热点数据的缓存过期或在缓存中不存在时,可能会导致大量的请求直接访问数据库,造成数据库压力过大。为了解决这个问题,可以使用互斥锁(如Redis的分布式锁)来控制只有一个请求去加载缓存数据,其他请求等待加载完成。缓存雪崩......
  • SpringSecurity中注解讲解
    目录[email protected]@PreAuthorize1.1.1开启注解1.1.2使用注解原生方法1.1.3使用注解自定义方法[email protected]@Secured2其他注解[email protected]@PreFilter3权限表达式1@EnableGlobalMethodSecurity@EnableGlobalMethodSecurity是Spring......
  • Websocket 全双工通信的协议
    Websocket介绍WebSocket使得客户端和服务器之间的数据交换变得更加简单,允许服务端主动向客户端推送数据。在WebSocketAPI中,浏览器和服务器只需要完成一次握手,两者之间就直接可以创建持久性的连接,并进行双向数据传输。Websocket特点1、较少的控制开销。在连接创建后,服务器......