我和我的团队一直在尝试使用 Spring Security 6 迁移到 Spring boot 3,但发现网络套接字存在问题。如果我们删除
@EnableWebSocketSecurity
注释一切正常,但关键是只允许经过身份验证的消息。
添加注释时,我们得到的只是前端的
ExecutorSubscribableChannel[clientInboundChannel]
错误和后端的access denied
。
我们还尝试按照官方文档 [https://docs.spring.io/spring-security/reference/servlet/integrations/websocket.html#websocket-sameorigin-csrf] 中的说明添加 csrf 令牌,但唯一的我们得到的是
The request object has been recycled and is no longer associated with this facade
错误消息。
就我们完全迷路而言,我们将感谢任何帮助:(
这里是关于我们的配置以及我们如何尝试创建连接的更多详细信息:
安全配置
@Configuration
@EnableWebSecurity
@EnableMethodSecurity(prePostEnabled = true)
internal class OpaqueTokenSecurityConfig {
@Value("\${spring.security.oauth2.client.provider.abc.token-uri}")
var tokenUri: String? = null
@Value("\${spring.security.oauth2.client.registration.abc.clientId}")
var clientId: String? = null
@Value("\${spring.security.oauth2.client.registration.abc.clientSecret}")
var clientSecret: String? = null
@Bean
fun customIntrospector(): OpaqueTokenIntrospector {
return CustomAuthoritiesOpaqueTokenIntrospector("$tokenUri/introspect", clientId, clientSecret)
}
@Bean
fun filterChain(http: HttpSecurity): SecurityFilterChain? {
http
.csrf().disable()
.sessionManagement().sessionCreationPolicy((SessionCreationPolicy.STATELESS))
.and()
.authorizeHttpRequests().anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED))
.and()
.oauth2ResourceServer()
.opaqueToken()
.introspector(customIntrospector())
return http.build()
}
@Bean
fun corsConfigurer(): WebMvcConfigurer {
return object : WebMvcConfigurer {
override fun addCorsMappings(registry: CorsRegistry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("*")
}
}
}
}
WebSocketsConfig
@Configuration
@EnableWebSocketMessageBroker
@EnableWebSocketSecurity
internal class WebSocketConfig : WebSocketMessageBrokerConfigurer {
override fun configureMessageBroker(config: MessageBrokerRegistry) {
config
.enableSimpleBroker("/topic")
}
override fun registerStompEndpoints(registry: StompEndpointRegistry) {
registry
.addEndpoint("/ws")
.setAllowedOriginPatterns("*")
}
@Configuration
open class WebSocketSecurityConfig {
fun messageAuthorizationManager(messages: MessageMatcherDelegatingAuthorizationManager.Builder): AuthorizationManager<Message<*>> {
messages
.anyMessage().authenticated()
return messages.build();
}
}
}
React 客户端:
let socket: CompatClient;
const client = Stomp.over(() => new WebSocket(`ws://localhost:8081/ws?access_token=${keycloak.token}`));
client.onWebSocketClose = () => {
// Do something
};
client.connect(
{},
() => {
socket = client;
// Do something
},
// eslint-disable-next-line no-console
(err: unknown) => console.log(err),
);