security整合websocket
快速使用
@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);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)
2020-09-11 VSCODE快速生成代码 和一些简单操作