最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

kotlin - How do I call a secure web socket using Stomp and Spring-Messaging from Postman? - Stack Overflow

programmeradmin0浏览0评论

I have the following demo app this includes a JWTDecoder I can add to fake real auth

@Configuration
@Profile("fake-jwt")
class FakeJwtConfig {
    @Bean
    fun jwtDecoder(): JwtDecoder {
        return JwtDecoder { token ->
            if (token != "test.token") {
                throw JwtException("Invalid token")
            }

            Jwt.withTokenValue(token)
                .header("alg", "none")
                .claim("sub", "user")
                .issuedAt(Instant.now())
                .expiresAt(Instant.now().plusSeconds(3600))
                .build()
        }
    }
}

and configuration to handle authorization

@Profile("secure")
@Configuration
@EnableWebSocketSecurity
class WebSocketSecurityConfig {
    @Bean
    fun messageAuthorizationManager(
        messages: MessageMatcherDelegatingAuthorizationManager.Builder
    ): AuthorizationManager<Message<*>> {
        messages
            // Next 2 lines are required for requests without auth.
            // Remove these if all paths require auth
            .simpTypeMatchers(SimpMessageType.CONNECT).permitAll()
            .simpTypeMatchers(SimpMessageType.DISCONNECT).permitAll()
            .simpDestMatchers("/app/status").permitAll()
            .simpDestMatchers("/app/hello").authenticated()
            .anyMessage().authenticated()
        return messages.build()
    }
}

I have a couple integration tests that seem to pass as expected, however, when I try to manually call the endpoint with something like

SEND
destination:/app/hello
Authorization: Bearer test.token

{"name":"test"}

It gets access denied...

Caused by: org.springframework.security.access.AccessDeniedException: Access Denied

The ones that do not require auth seem to work fine like

SEND
destination:/app/status

{"name":"test"}

work fine so I am confused why it works with test but I can't get it to work manually?

Full project here to be clear I am using hex-encoding etc...

I have the following demo app this includes a JWTDecoder I can add to fake real auth

@Configuration
@Profile("fake-jwt")
class FakeJwtConfig {
    @Bean
    fun jwtDecoder(): JwtDecoder {
        return JwtDecoder { token ->
            if (token != "test.token") {
                throw JwtException("Invalid token")
            }

            Jwt.withTokenValue(token)
                .header("alg", "none")
                .claim("sub", "user")
                .issuedAt(Instant.now())
                .expiresAt(Instant.now().plusSeconds(3600))
                .build()
        }
    }
}

and configuration to handle authorization

@Profile("secure")
@Configuration
@EnableWebSocketSecurity
class WebSocketSecurityConfig {
    @Bean
    fun messageAuthorizationManager(
        messages: MessageMatcherDelegatingAuthorizationManager.Builder
    ): AuthorizationManager<Message<*>> {
        messages
            // Next 2 lines are required for requests without auth.
            // Remove these if all paths require auth
            .simpTypeMatchers(SimpMessageType.CONNECT).permitAll()
            .simpTypeMatchers(SimpMessageType.DISCONNECT).permitAll()
            .simpDestMatchers("/app/status").permitAll()
            .simpDestMatchers("/app/hello").authenticated()
            .anyMessage().authenticated()
        return messages.build()
    }
}

I have a couple integration tests that seem to pass as expected, however, when I try to manually call the endpoint with something like

SEND
destination:/app/hello
Authorization: Bearer test.token

{"name":"test"}

It gets access denied...

Caused by: org.springframework.security.access.AccessDeniedException: Access Denied

The ones that do not require auth seem to work fine like

SEND
destination:/app/status

{"name":"test"}

work fine so I am confused why it works with test but I can't get it to work manually?

Full project here to be clear I am using hex-encoding etc...

Share Improve this question edited Feb 6 at 18:18 dur 17k26 gold badges88 silver badges143 bronze badges asked Feb 5 at 15:23 JackieJackie 23.5k41 gold badges169 silver badges328 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

In Postman, you'll need to set Authorization inside headers instead of in the messages.

In your code, .oauth2ResourceServer { oauth2 -> oauth2.jwt { } } expects a valid bearer token in the Authorization header. The security context is propagated to WebSocket security as described here.

In your controller method, you can log the Authentication like this to verify it's working.

    @MessageMapping("/hello")
    @SendTo("/topic/greetings")
    fun greeting(
        message: TestMessage,
        authentication: Optional<Authentication>
    ): Greeting {
        logger.info(message.toString())
        authentication.ifPresent {
            logger.info("Authentication: {}", it)
        }
        return Greeting("Hello, ${message.name}!")
    }

Log Excerpt

Logs when sending two messages after connect. Note Securing GET /ws followed by Set SecurityContextHolder to JwtAuthenticationToken.

2025-02-06T14:59:27.354+01:00 DEBUG 3224140 --- [websocket] [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Securing GET /ws
2025-02-06T14:59:27.360+01:00 DEBUG 3224140 --- [websocket] [nio-8080-exec-1] o.s.s.o.s.r.a.JwtAuthenticationProvider  : Authenticated token
2025-02-06T14:59:27.361+01:00 DEBUG 3224140 --- [websocket] [nio-8080-exec-1] .s.r.w.a.BearerTokenAuthenticationFilter : Set SecurityContextHolder to JwtAuthenticationToken [Principal=org.springframework.security.oauth2.jwt.Jwt@3d7ec21, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=127.0.0.1, SessionId=null], Granted Authorities=[]]
2025-02-06T14:59:27.363+01:00 DEBUG 3224140 --- [websocket] [nio-8080-exec-1] o.s.security.web.FilterChainProxy        : Secured GET /ws
2025-02-06T14:59:36.814+01:00 DEBUG 3224140 --- [websocket] [nio-8080-exec-2] .s.m.a.i.AuthorizationChannelInterceptor : Authorizing message send
2025-02-06T14:59:36.815+01:00 DEBUG 3224140 --- [websocket] [nio-8080-exec-2] .s.m.a.i.AuthorizationChannelInterceptor : Authorized message send
2025-02-06T14:59:36.867+01:00  INFO 3224140 --- [websocket] [nboundChannel-1] e.w.controller.WebSocketController       : TestMessage(name=test)
2025-02-06T14:59:36.868+01:00  INFO 3224140 --- [websocket] [nboundChannel-1] e.w.controller.WebSocketController       : Authentication: JwtAuthenticationToken [Principal=org.springframework.security.oauth2.jwt.Jwt@3d7ec21, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=127.0.0.1, SessionId=null], Granted Authorities=[]]
2025-02-06T14:59:40.626+01:00 DEBUG 3224140 --- [websocket] [nio-8080-exec-3] .s.m.a.i.AuthorizationChannelInterceptor : Authorizing message send
2025-02-06T14:59:40.626+01:00 DEBUG 3224140 --- [websocket] [nio-8080-exec-3] .s.m.a.i.AuthorizationChannelInterceptor : Authorized message send
2025-02-06T14:59:40.627+01:00  INFO 3224140 --- [websocket] [nboundChannel-4] e.w.controller.WebSocketController       : TestMessage(name=test)
2025-02-06T14:59:40.627+01:00  INFO 3224140 --- [websocket] [nboundChannel-4] e.w.controller.WebSocketController       : Authentication: JwtAuthenticationToken [Principal=org.springframework.security.oauth2.jwt.Jwt@3d7ec21, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=127.0.0.1, SessionId=null], Granted Authorities=[]]

Tested and verified with code from OP.

发布评论

评论列表(0)

  1. 暂无评论