使用 spring 发送特定于用户的消息
Send User-specific message with spring
我有一个端点 (/create),它有一些逻辑,需要 3-4 分钟来处理,所以我使用了 rabbitmq,一旦端点收到请求,它就会获取正文和 post rabbitmq中的消息,监听器监听消息并处理请求现在我想通知用户他的请求处理成功
- websocket 是否符合此要求的正确选择
- 还有其他更好的方法可以实现我的目标吗?
所以我继续使用 websocket,因为我使用的是基于 oauth 的身份验证,我无法获得 web-socket 工作
这是我编写的代码:
SocketConfig.java
@Configuration
@EnableWebSocketMessageBroker
public class SocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic","/secured/queue");
//config.setApplicationDestinationPrefixes("/app");
//config.setUserDestinationPrefix("/secured/user");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/secured/messagereg").setAllowedOrigins("*").withSockJS();
}
SocketHandler.java
@Configuration
public class SocketHandler extends AbstractSecurityWebSocketMessageBrokerConfigurer {
@Override
protected boolean sameOriginDisabled() {
return true;
}
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
.simpDestMatchers("/secured/**", "/secured/**/**").authenticated()
.anyMessage().authenticated();
}
}
WebSecurityConfig.java
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Profile("!test")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private Auth0PropertyConfig config;
@Override
protected void configure(HttpSecurity http) throws Exception {
JwtWebSecurityConfigurer
.forRS256(config.getAudience(), config.getIssuer())
.configure(http)
.cors()
.and()
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
;
}
}
clientCode
const socket = new SockJs("/secured/messagereg/?access_token="+token);
this.setState({ clientRef: Stomp.over(socket) }, () =>
this.state.clientRef.connect({},
frame => {
this.setState({ connection: true });
this.state.clientRef.subscribe("/user/secured/queue/reply", message => {
console.log("asd received ----------" + message.body);
this.setState(prevs => ({
message: [...prevs.message, message]
}));
});
},
error => {
console.log("Stomp protocol error." + error);
}
)
);
我在连接到套接字时收到 401 未经授权。
我认为:推送消息传递模式(例如使用 STOMP)适合这种情况,但这最终取决于您的架构原则。您还可以轮询服务器以获取结果(使用 REST API),它既有优点(共享安全架构)也有缺点(客户端代码、流量和 reaction-time 开销)。
答案:
为了让您的代码正常工作,我认为您的 SocketConfig.java
中还需要一种方法,它会连接到您的 OAUTH 过滤器(或您可能已有的任何方法)。
重要 - websocket 身份验证不重用现有的 Spring 安全上下文 。这就是为什么你需要再次实现 auth,例如在 SocketConfig
class 中使用 WebSocketMessageBrokerConfigurer
的方法 configureClientInboundChannel
.
以下示例假定您之前已经获得了OAUTH token,并且它仅用于重新验证websocket 连接。在 StompHeaderAccessor
(倒数第三行)中设置用户引用将使您的代码能够向正确的用户发送消息。
它还要求在消息 header 中设置 OAUTH 令牌,而不是示例中的端点参数。我认为这对于 websocks 消息传递可能更安全,因为如果您使用 wss.
消息本身在协议级别加密
@Autowired
private YourOauthService auth;
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new ChannelInterceptor() {
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor =
MessageHeaderAccessor.getAccessor(message,
StompHeaderAccessor.class);
if (StompCommand.CONNECT.equals(accessor.getCommand())) {
String token = accessor.removeNativeHeader("Authorization").get(0);
Authentication user = auth.getAuthentication(token);
accessor.setUser(user);
}
return message;
}
});
}
我在 https://robertleggett.wordpress.com/2015/05/27/websockets-with-spring-spring-security/
中找到了一些更有趣的示例
我有一个端点 (/create),它有一些逻辑,需要 3-4 分钟来处理,所以我使用了 rabbitmq,一旦端点收到请求,它就会获取正文和 post rabbitmq中的消息,监听器监听消息并处理请求现在我想通知用户他的请求处理成功
- websocket 是否符合此要求的正确选择
- 还有其他更好的方法可以实现我的目标吗?
所以我继续使用 websocket,因为我使用的是基于 oauth 的身份验证,我无法获得 web-socket 工作
这是我编写的代码:
SocketConfig.java
@Configuration
@EnableWebSocketMessageBroker
public class SocketConfig implements WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/topic","/secured/queue");
//config.setApplicationDestinationPrefixes("/app");
//config.setUserDestinationPrefix("/secured/user");
}
@Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/secured/messagereg").setAllowedOrigins("*").withSockJS();
}
SocketHandler.java
@Configuration
public class SocketHandler extends AbstractSecurityWebSocketMessageBrokerConfigurer {
@Override
protected boolean sameOriginDisabled() {
return true;
}
@Override
protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
messages
.simpDestMatchers("/secured/**", "/secured/**/**").authenticated()
.anyMessage().authenticated();
}
}
WebSecurityConfig.java
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
@Profile("!test")
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private Auth0PropertyConfig config;
@Override
protected void configure(HttpSecurity http) throws Exception {
JwtWebSecurityConfigurer
.forRS256(config.getAudience(), config.getIssuer())
.configure(http)
.cors()
.and()
.csrf().disable()
.authorizeRequests()
.anyRequest().authenticated()
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
;
}
}
clientCode
const socket = new SockJs("/secured/messagereg/?access_token="+token);
this.setState({ clientRef: Stomp.over(socket) }, () =>
this.state.clientRef.connect({},
frame => {
this.setState({ connection: true });
this.state.clientRef.subscribe("/user/secured/queue/reply", message => {
console.log("asd received ----------" + message.body);
this.setState(prevs => ({
message: [...prevs.message, message]
}));
});
},
error => {
console.log("Stomp protocol error." + error);
}
)
);
我在连接到套接字时收到 401 未经授权。
我认为:推送消息传递模式(例如使用 STOMP)适合这种情况,但这最终取决于您的架构原则。您还可以轮询服务器以获取结果(使用 REST API),它既有优点(共享安全架构)也有缺点(客户端代码、流量和 reaction-time 开销)。
答案:
为了让您的代码正常工作,我认为您的 SocketConfig.java
中还需要一种方法,它会连接到您的 OAUTH 过滤器(或您可能已有的任何方法)。
重要 - websocket 身份验证不重用现有的 Spring 安全上下文 。这就是为什么你需要再次实现 auth,例如在 SocketConfig
class 中使用 WebSocketMessageBrokerConfigurer
的方法 configureClientInboundChannel
.
以下示例假定您之前已经获得了OAUTH token,并且它仅用于重新验证websocket 连接。在 StompHeaderAccessor
(倒数第三行)中设置用户引用将使您的代码能够向正确的用户发送消息。
它还要求在消息 header 中设置 OAUTH 令牌,而不是示例中的端点参数。我认为这对于 websocks 消息传递可能更安全,因为如果您使用 wss.
消息本身在协议级别加密@Autowired
private YourOauthService auth;
@Override
public void configureClientInboundChannel(ChannelRegistration registration) {
registration.interceptors(new ChannelInterceptor() {
@Override
public Message<?> preSend(Message<?> message, MessageChannel channel) {
StompHeaderAccessor accessor =
MessageHeaderAccessor.getAccessor(message,
StompHeaderAccessor.class);
if (StompCommand.CONNECT.equals(accessor.getCommand())) {
String token = accessor.removeNativeHeader("Authorization").get(0);
Authentication user = auth.getAuthentication(token);
accessor.setUser(user);
}
return message;
}
});
}
我在 https://robertleggett.wordpress.com/2015/05/27/websockets-with-spring-spring-security/
中找到了一些更有趣的示例