基于OAuth的设置身份验证/授权

问题描述 投票:0回答:1

spring: security: oauth2: resourceserver: jwt: issuer-uri: ... audiences: - ...

@Configuration @EnableWebSecurity class SecurityConfig( @Autowired(required = false) private val requestLoggingFilter: RequestLoggingFilter? ) { @Bean fun filterChain(http: HttpSecurity): SecurityFilterChain { http .csrf { it.disable() } .oauth2ResourceServer { oauth2 -> oauth2.jwt { } } .authorizeHttpRequests { auth -> auth .requestMatchers("/qr/**").authenticated() .anyRequest().permitAll() } .sessionManagement { session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS) } .... return http.build() }

this的功能如预期的那样。我也有一个工作的Web插座端点...
@Configuration
@EnableWebSocketMessageBroker
class WebsocketConfig : WebSocketMessageBrokerConfigurer {

    override fun configureMessageBroker(config: MessageBrokerRegistry) {
        config.enableSimpleBroker("/topic")
        config.setApplicationDestinationPrefixes("/app")
    }

    override fun registerStompEndpoints(registry: StompEndpointRegistry) {
        registry.addEndpoint("/gs-guide-websocket")
    }
}
...
    @MessageMapping("/hello")
    @SendTo("/topic/greetings")
    @Throws(Exception::class)
    fun greeting(message: Any): Greeting {
        ....
    }
现在我尝试添加安全性,因此我将以下内容添加到安全配置...

@Configuration @EnableWebSecurity @EnableWebSocketSecurity class SecurityConfig( @Autowired(required = false) private val requestLoggingFilter: RequestLoggingFilter? ) { ... @Bean fun messageAuthorizationManager(messages: MessageMatcherDelegatingAuthorizationManager.Builder): AuthorizationManager<Message<*>> { messages .simpDestMatchers("/topic/**").authenticated() return messages.build() } }
但是当我尝试打电话给类似的东西时

SEND destination:/app/hello Authorization: Bearer ey... {"name":"test"}

我仍然得到
Caused by: org.springframework.security.access.AccessDeniedException: Access Denied at org.springframework.security.messaging.access.intercept.AuthorizationChannelInterceptor.preSend(AuthorizationChannelInterceptor.java:75) ~[spring-security-messaging-6.4.2.jar:6.4.2] at org.springframework.messaging.support.AbstractMessageChannel$ChannelInterceptorChain.applyPreSend(AbstractMessageChannel.java:181) ~[spring-messaging-6.2.2.jar:6.2.2] at org.springframework.messaging.support.AbstractMessageChannel.send(AbstractMessageChannel.java:135) ~[spring-messaging-6.2.2.jar:6.2.2] ... 44 common frames omitted

完全没有标题。同样的令牌在常规的网络端点上正常工作,所以我缺少什么?
当我添加以下内容...

logging: level: org.springframework.security: DEBUG org.springframework.messaging: DEBUG org.springframework.web.socket: DEBUG org.springframework.security.oauth2: TRACE
我将终点更改为ws,但我不知道

2025-02-02T10:47:16.609-05:00 DEBUG 88460 --- [love-monkey] [nio-7080-exec-3] o.s.w.s.s.s.WebSocketHttpRequestHandler : GET /ws 2025-02-02T10:47:16.641-05:00 DEBUG 88460 --- [love-monkey] [nio-7080-exec-3] s.w.s.h.LoggingWebSocketHandlerDecorator : New StandardWebSocketSession[id=e28c3083-e231-c00d-dc20-2cdb4d01ecac, uri=ws://....net/ws] 2025-02-02T10:47:18.340-05:00 DEBUG 88460 --- [love-monkey] [nio-7080-exec-4] .s.m.a.i.AuthorizationChannelInterceptor : Authorizing message send 2025-02-02T10:47:18.341-05:00 DEBUG 88460 --- [love-monkey] [nio-7080-exec-4] .s.m.a.i.AuthorizationChannelInterceptor : Failed to authorize message with authorization manager org.springframework.security.messaging.access.intercept.MessageMatcherDelegatingAuthorizationManager@5a4d7ce9 and result AuthorizationDecision [granted=false] 2025-02-02T10:47:18.341-05:00 DEBUG 88460 --- [love-monkey] [nio-7080-exec-4] o.s.w.s.m.StompSubProtocolHandler : Failed to send message to MessageChannel in session e28c3083-e231-c00d-dc20-2cdb4d01ecac org.springframework.messaging.MessageDeliveryException: Failed to send message to ExecutorSubscribableChannel[clientInboundChannel]

也是一个示例项目,如果您想玩,也有相同的问题

Tl;dr th这个答案是关于在Op

中撰写this Repo的代码,并创建一个使用携带者令牌的测试环境。
kotlin spring-security websocket spring-websocket
1个回答
0
投票

update

成功创建了使用

.httpBasic创建设置后,我将此答案更新为使用.oauth2ResourceServer

。 securityConfig

非常简单;它允许所有重新要求添加并添加SecurityFilterChain

/ws

customcsrfChannelInterceptor&webSocketSecurityConfig

这有点棘手,因为CSRF-Header无法关闭,但是我在this this Answer.中发现了一个hack。

.oauth2ResourceServer

我们需要一个从携带者令牌中提取角色。可以在应用程序中完成。
@Configuration class SecurityConfig { @Bean fun filterChain(http: HttpSecurity): SecurityFilterChain { http .csrf { csrf -> csrf.disable() } .sessionManagement { session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS) } .oauth2ResourceServer { oauth2 -> oauth2.jwt { } } .authorizeHttpRequests { auth -> auth .requestMatchers(HttpMethod.GET, "/ws").permitAll() .anyRequest().authenticated() } return http.build() } }
WebsocketController

llet的log the the the Controller
// https://stackoverflow.com/a/77057255/14072498
@Component("csrfChannelInterceptor")
class CustomCsrfChannelInterceptor : ChannelInterceptor {
    override fun preSend(
        message: Message<*>,
        channel: MessageChannel
    ): Message<*> {
        return message
    }
}

@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/hello").hasRole("USER")
            .anyMessage().authenticated()
        return messages.build()
    }
}

测试

为了避免使用真正的携带者令牌,让我们在测试上下文中添加模拟JwtAuthenticationConverter

spring:
  security:
    oauth2:
      resourceserver:
        jwt:
          authorities-claim-name: roles
          authority-prefix: ROLE_

测试尚未提出任何断言,但可以让您进行一些测试。
Authentication

	

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.