我如何将一个携带者令牌添加到 @stomp/stompjs,甚至只是常规的JS websocket? 我有一个简单的春季启动应用程序,使用弹簧安全性来控制对Web插座主题的访问。这是使用OAuth用携带者令牌对用户进行身份验证的。除了我...

问题描述 投票:0回答:1
import { Client } from '@stomp/stompjs'; const WebSocketClient = () => { ... const stompClient = new Client({ brokerURL, onConnect: () => { setConnected(true); setError(''); setCanRetryGreetings(true); // Subscribe to public status topic stompClient.subscribe('/topic/greeting', (message) => { setMessages(prev => [...prev, `Status: ${message.body}`]); }); // Announce presence stompClient.publish({ destination: '/app/hello', body: 'Client connected' }); }, onDisconnect: () => { setConnected(false); setCanRetryGreetings(true); }, onError: (err) => { setError(`Connection error: ${err.message}`); } });

问题是我不确定如何设置授权标题。这是工作邮递员请求的样子...

如果我卸下标头,这是完美的,失败了。但是看来您不能为Stomp中的握手进行自定义标题。那么我该如何工作呢? enter image description here完整项目可在此处提供

那么,如何让Stomp Client与Postman One相同?我需要使用原始的Web插座而不是Stomp吗?是否有更好的方法可以将Oauth与Stomp一起使用? 我尝试使用类似结果的sockjs

尝试。

看起来像是问题的是连接具有auth标题

但订阅不是

the nevermind,即使有授权标题 enter image description here

boolean granted = this.authorizationStrategy.isGranted(authentication.get());

enter image description here

表示,它不是使用auth标题来确定请求是否来自已认证的某人。

我也注意到它在邮递员中“工作”时没有订阅消息 enter image description here

我这样做了...
首先订阅和发布使用标头发送授权令牌...

client.publish( { destination: publishTopic, body: JSON.stringify({ message: statusMessage, name: "Test Message" }), headers: { "Authorization": `Bearer test.token` } } ); ... stompClient.subscribe( subscribeTopic, (message) => { ... }, { "Authorization": `Bearer test.token` }); enter image description here 在弹簧侧的next我需要添加一些东西以从标题中正确创建授权者...

private fun authenticateAndAuthorize(auth: Authentication?, message: Message<*>): AuthorizationDecision { val nativeHeaders = message.headers["nativeHeaders"] as? Map<String, List<String>> val authHeader = nativeHeaders?.get("Authorization")?.firstOrNull() return try { if (auth != null && auth.isAuthenticated && auth !is AnonymousAuthenticationToken) { logger.debug("User already authenticated: ${auth.name}") AuthorizationDecision(true) } else if (authHeader != null && authHeader.startsWith("Bearer ")) { val token = authHeader.substring(7) val authenticatedUser = authenticationProvider.authenticate(BearerTokenAuthenticationToken(token)) SecurityContextHolder.getContext().authentication = authenticatedUser logger.debug("Successfully authenticated token for user: ${authenticatedUser.name}") AuthorizationDecision(true) } else { logger.debug("No valid authentication found") AuthorizationDecision(false) } } catch (e: Exception) { logger.error("Authentication failed: ${e.message}", e) AuthorizationDecision(false) } }

我需要在安全配置中进行设置...

@Profile("secure") @Configuration @EnableWebSocketSecurity class WebSocketSecurityConfig(jwtDecoder: JwtDecoder) { private val logger: Logger = LoggerFactory.getLogger(WebSocketSecurityConfig::class.java) private val authenticationProvider = JwtAuthenticationProvider(jwtDecoder) @Bean fun messageAuthorizationManager( messages: MessageMatcherDelegatingAuthorizationManager.Builder ): AuthorizationManager<Message<*>> { val tokenAuthorizationManager = AuthorizationManager<MessageAuthorizationContext<*>> { auth, context -> authenticateAndAuthorize(auth.get(), context.message) } messages .simpTypeMatchers(SimpMessageType.CONNECT, SimpMessageType.DISCONNECT).permitAll() .simpDestMatchers("/app/status", "/topic/status").permitAll() .anyMessage().access(tokenAuthorizationManager) return messages.build() } private fun authenticateAndAuthorize(auth: Authentication?, message: Message<*>): AuthorizationDecision { val nativeHeaders = message.headers["nativeHeaders"] as? Map<String, List<String>> val authHeader = nativeHeaders?.get("Authorization")?.firstOrNull() return try { if (auth != null && auth.isAuthenticated && auth !is AnonymousAuthenticationToken) { logger.debug("User already authenticated: ${auth.name}") AuthorizationDecision(true) } else if (authHeader != null && authHeader.startsWith("Bearer ")) { val token = authHeader.substring(7) val authenticatedUser = authenticationProvider.authenticate(BearerTokenAuthenticationToken(token)) SecurityContextHolder.getContext().authentication = authenticatedUser logger.debug("Successfully authenticated token for user: ${authenticatedUser.name}") AuthorizationDecision(true) } else { logger.debug("No valid authentication found") AuthorizationDecision(false) } } catch (e: Exception) { logger.error("Authentication failed: ${e.message}", e) AuthorizationDecision(false) } } }
javascript websocket spring-websocket stomp stompjs
1个回答
0
投票
这允许进行身份验证。但是,如果您需要这样的校长

@MessageMapping("/private-message") @SendToUser("/chat/messages") fun addUser( @Payload chatMessage: String, principal: Principal ): String { return "Hello, ${principal.name}! You sent: $chatMessage" }

您还需要一个频道拦截器来设置JWT令牌的主值。这是我的例子...

@Configuration @EnableWebSocketMessageBroker class WebSocketConfig : WebSocketMessageBrokerConfigurer { ... override fun configureClientInboundChannel(registration: ChannelRegistration) { registration.interceptors(object : ChannelInterceptor { override fun preSend(message: Message<*>, channel: MessageChannel): Message<*> { val accessor = MessageHeaderAccessor.getAccessor(message, SimpMessageHeaderAccessor::class.java) val messageType = accessor?.messageType // Only process CONNECT, SUBSCRIBE, and SEND messages if (messageType == SimpMessageType.CONNECT || messageType == SimpMessageType.SUBSCRIBE || messageType == SimpMessageType.MESSAGE) { val auth = SecurityContextHolder.getContext().authentication if (auth != null && auth.isAuthenticated) { accessor?.user = auth } } return message } }) } }
现在似乎正如预期的。
    

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