my application is structured as follows:
Spring Boot
WebSocket Config
@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);
Map<String, Object> authUserInfo = new HashMap<>();
if (accessor.getHeader("simpUser") != null && BearerTokenAuthentication.class.isAssignableFrom(accessor.getHeader("simpUser").getClass())) {
BearerTokenAuthentication auth = (BearerTokenAuthentication) accessor.getHeader("simpUser");
authUserInfo = auth.getTokenAttributes();
}
if (accessor.getNativeHeader("Authorization") != null) {
String token = accessor.getFirstNativeHeader("Authorization");
authUserInfo.put("Authorization", token);
}
log.info("WebSocket - Msg type: {}. User Info: {}", accessor.getCommand(), authUserInfo);
return message;
}
});
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/websocket-endpoint").setAllowedOriginPatterns("*");
registry.addEndpoint("/websocket-endpoint").setAllowedOriginPatterns("*").withSockJS();
}
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/messages");
}
Security Config
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public class SocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages.anyMessage().authenticated();
}
@Override
protected boolean sameOriginDisabled() {
return true;
}
}
...
@Configuration
@Order(2)
public static class SecurityConfig extends WebSecurityConfigurerAdapter {
@Value("${spring.security.oauth2.resourceserver.introspection-uri}")
private String introspectionUri;
@Value("${spring.security.oauth2.resourceserver.client-id}")
private String clientId;
@Value("${spring.security.oauth2.resourceserver.client-secret}")
private String clientSecret;
@Bean
public OpaqueTokenIntrospector introspector() {
return new NimbusOpaqueTokenIntrospector(introspectionUri, clientId, clientSecret);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http //
.requestMatchers().antMatchers("/api/**", "/websocket-endpoint/**", "/websocket-endpoint", "/messages/**).and() //
.authorizeRequests(authorizeRequests -> authorizeRequests.anyRequest().authenticated()) // .oauth2ResourceServer(OAuth2ResourceServerConfigurer::opaqueToken).cors().and() //
.csrf().disable();
}
}
What I want is every websocket message (CONNECT, SUBSCRIBE, etc ...) to be authenticated via my oauth2 configuration. This works with my Java test client:
public static void main(String[] args) {
if (args == null || args.length < 1) {
throw new RuntimeException();
}
WebSocketHttpHeaders headers = new WebSocketHttpHeaders();
headers.add("Authorization", "Bearer " + args[0]);
WebSocketClient client = new StandardWebSocketClient();
WebSocketStompClient stompClient = new WebSocketStompClient(client);
stompClient.setMessageConverter(new MappingJackson2MessageConverter());
StompSessionHandler sessionHandler = new MyStompSessionHandler();
stompClient.connect("ws://localhost:7081/websocket-endpoint", headers, sessionHandler);
new Scanner(System.in).nextLine();
}
public static class MyStompSessionHandler extends StompSessionHandlerAdapter {
@Override
public void afterConnected(StompSession session, StompHeaders connectedHeaders) {
log.info("New session established : " + session.getSessionId());
session.subscribe("/messages/messages-in-a-bottle", this);
log.info("Subscribed");
}
@Override
public void handleTransportError(StompSession session, Throwable exception) {
log.error("Got an exception", exception);
}
@Override
public void handleException(StompSession session, StompCommand command, StompHeaders headers, byte[] payload, Throwable exception) {
log.error("Got an exception", exception);
}
@Override
public Type getPayloadType(StompHeaders headers) {
return MyResource.class;
}
@Override
public void handleFrame(StompHeaders headers, Object payload) {
MyResource msg = (MyResource) payload;
log.info("Received : " + msg);
}
}
but i can't get it to work with Angular and rx-stomp. Could someone show me a guide on how to set up a connect / subscribe on Angular (with access-token Oauth2)? I also tried with SockJS and STOMP but couldn't