如何基于用户权限使用Spring-Websocket拒绝主题订阅

35
我正在实现股票应用程序的一个版本,其中服务器能够根据用户权限拒绝某些主题的订阅。在spring-websocket中有没有这样做的方法?
例如: 在股票示例项目中,我们有三个工具的价格主题:Apple、Microsoft和Google,并且有两个用户:User1和User2。 User1应该可以访问Apple和Microsoft,User2只能访问Google。
如果User1订阅Google,则他应该收到拒绝响应,并且消息不应该广播给他。
2个回答

60

感谢Rossen Stoyanchev在GitHub上的回答(链接),我通过向入站通道添加拦截器来解决了这个问题。需要更改spring-websocket-portfolio演示应用程序的内容如下:

更改WebSocket配置:

public void configureClientInboundChannel(ChannelRegistration registration) {
    registration.setInterceptors(new TopicSubscriptionInterceptor());
}

拦截器大概是这样的:

public class TopicSubscriptionInterceptor extends ChannelInterceptorAdapter {
    private static Logger logger = org.slf4j.LoggerFactory.getLogger(TopicSubscriptionInterceptor.class);

    @Override
    public Message<?> preSend(Message<?> message, MessageChannel channel) {
        StompHeaderAccessor headerAccessor= StompHeaderAccessor.wrap(message);
        if (StompCommand.SUBSCRIBE.equals(headerAccessor.getCommand())) {
            Principal userPrincipal = headerAccessor.getUser();
            if (!validateSubscription(userPrincipal, headerAccessor.getDestination())) {
                throw new IllegalArgumentException("No permission for this topic");
            }
        }
        return message;
    }

    private boolean validateSubscription(Principal principal, String topicDestination) {
        if (principal == null) {
            // Unauthenticated user
            return false;
        }
        logger.debug("Validate subscription for {} to topic {}", principal.getName(), topicDestination);
        // Additional validation logic coming here
        return true;
    }
}

2
你好,我正在使用Spring Websocket,并遇到了与您类似的情况。您能告诉我在调用headerAccessor.getHeader("simpUser")时值来自何处吗?WebsocketHttpHeaders只能在客户端为标头添加字符串值。 - Dave Pateral
2
抛出 org.springframework.messaging.MessagingException 更好。 - LoganMzz

6

从Spring 5.x开始,如果您正在扩展AbstractSecurityWebSocketMessageBrokerConfigurer,则正确的覆盖方法以附加拦截器是customizeClientInboundChannel

@Override
public void customizeClientInboundChannel(ChannelRegistration registration) {
    registration.interceptors(new TopicSubscriptionInterceptor());
}

1
最好使用WebSocketMessageBrokerConfigurer,因为AbstractSecurityWebSocketMessageBrokerConfigurer已经被废弃很久了 :) - Walnussbär

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接