我记得在我正在做的一个项目中,遇到了同样的问题。由于我无法使用Spring文档找到解决方案——以及其他有关堆栈溢出的答案对我不起作用——所以我最终创建了一个解决方案。
技巧本质上是强制应用程序在WebSocket连接请求上对用户进行身份验证。要做到这一点,您需要一个拦截此类事件的类,然后一旦您控制了该类,就可以调用您的身份验证逻辑。
创建实现Spring的类
ChannelInterceptorAdapter
. 在这个类中,可以注入执行实际身份验证所需的任何bean。我的示例使用基本身份验证:
@Component
public class WebSocketAuthInterceptorAdapter extends ChannelInterceptorAdapter {
@Autowired
private DaoAuthenticationProvider userAuthenticationProvider;
@Override
public Message<?> preSend(final Message<?> message, final MessageChannel channel) throws AuthenticationException {
final StompHeaderAccessor accessor = MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);
StompCommand cmd = accessor.getCommand();
if (StompCommand.CONNECT == cmd || StompCommand.SEND == cmd) {
Authentication authenticatedUser = null;
String authorization = accessor.getFirstNativeHeader("Authorization:);
String credentialsToDecode = authorization.split("\\s")[1];
String credentialsDecoded = StringUtils.newStringUtf8(Base64.decodeBase64(credentialsToDecode));
String[] credentialsDecodedSplit = credentialsDecoded.split(":");
final String username = credentialsDecodedSplit[0];
final String password = credentialsDecodedSplit[1];
authenticatedUser = userAuthenticationProvider.authenticate(new UsernamePasswordAuthenticationToken(username, password));
if (authenticatedUser == null) {
throw new AccessDeniedException();
}
SecurityContextHolder.getContext().setAuthentication(authenticatedUser);
accessor.setUser(authenticatedUser);
}
return message;
}
然后,在你的
WebSocketConfig
类,您需要注册拦截器。将上述类作为bean添加并注册。在这些更改之后,您的类将如下所示:
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
@Autowired
private WebSocketAuthInterceptorAdapter authInterceptorAdapter;
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic");
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/app").withSockJS();
}
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.setInterceptors(authInterceptorAdapter);
super.configureClientInboundChannel(registration);
}
}
显然,身份验证逻辑的细节由您决定。您可以调用JWT服务或您正在使用的任何服务。