中小企业网站推广,东莞做网站建设,传统的网站开发模式和mvc,手机网站返回跳转目录 一、需要了解的事项二、依赖三、WebSocket 配置3.1 、简单的消息代理3.2 、Spring安全配置 一、需要了解的事项
http和WebSocket的安全链和安全配置是完全独立的。SpringAuthenticationProvider根本不参与 Websocket 身份验证。将要给出的示例中#xff0c;身份验证不会… 目录 一、需要了解的事项二、依赖三、WebSocket 配置3.1 、简单的消息代理3.2 、Spring安全配置 一、需要了解的事项
http和WebSocket的安全链和安全配置是完全独立的。SpringAuthenticationProvider根本不参与 Websocket 身份验证。将要给出的示例中身份验证不会发生在 HTTP 协商端点上因为 JavaScript STOMPwebsocket库不会随 HTTP 请求一起发送必要的身份验证标头。一旦在 CONNECT 请求上设置用户( simpUser) 将被存储在 websocket 会话中并且以后的消息将不再需要进行身份验证。
二、依赖
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-websocket/artifactId
/dependency
dependencygroupIdorg.springframework/groupIdartifactIdspring-messaging/artifactId
/dependency
dependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-security/artifactId
/dependency
dependencygroupIdorg.springframework.security/groupIdartifactIdspring-security-messaging/artifactId
/dependency三、WebSocket 配置
3.1 、简单的消息代理
Configuration
EnableWebSocketMessageBroker
public class WebSocketConfig extends WebSocketMessageBrokerConfigurer {Overridepublic void configureMessageBroker(final MessageBrokerRegistry config) {config.enableSimpleBroker(/queue/topic);config.setApplicationDestinationPrefixes(/app);}Overridepublic void registerStompEndpoints(final StompEndpointRegistry registry) {registry.addEndpoint(stomp); setAllowedOrigins(*)}
}3.2 、Spring安全配置
由于 Stomp 协议依赖于第一个 HTTP 请求因此需要授权对 stomp 握手端点的 HTTP 调用。
Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {Overrideprotected void configure(final HttpSecurity http) throws Exceptionhttp.httpBasic().disable().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().authorizeRequests().antMatchers(/stomp).permitAll().anyRequest().denyAll();}
}然后创建一个负责验证用户身份的服务。
Component
public class WebSocketAuthenticatorService {public UsernamePasswordAuthenticationToken getAuthenticatedOrFail(final String username, final String password) throws AuthenticationException {if (username null || username.trim().isEmpty()) {throw new AuthenticationCredentialsNotFoundException(Username was null or empty.);}if (password null || password.trim().isEmpty()) {throw new AuthenticationCredentialsNotFoundException(Password was null or empty.);}if (fetchUserFromDb(username, password) null) {throw new BadCredentialsException(Bad credentials for user username);}return new UsernamePasswordAuthenticationToken(username,null,Collections.singleton((GrantedAuthority) () - USER) // 必须给至少一个角色);}
}接着需要创建一个拦截器它将设置“simpUser”标头或在 CONNECT 消息上抛出“AuthenticationException”。
Component
public class AuthChannelInterceptorAdapter extends ChannelInterceptor {private static final String USERNAME_HEADER login;private static final String PASSWORD_HEADER passcode;private final WebSocketAuthenticatorService webSocketAuthenticatorService;Injectpublic AuthChannelInterceptorAdapter(final WebSocketAuthenticatorService webSocketAuthenticatorService) {this.webSocketAuthenticatorService webSocketAuthenticatorService;}Overridepublic Message? preSend(final Message? message, final MessageChannel channel) throws AuthenticationException {final StompHeaderAccessor accessor MessageHeaderAccessor.getAccessor(message, StompHeaderAccessor.class);if (StompCommand.CONNECT accessor.getCommand()) {final String username accessor.getFirstNativeHeader(USERNAME_HEADER);final String password accessor.getFirstNativeHeader(PASSWORD_HEADER);final UsernamePasswordAuthenticationToken user webSocketAuthenticatorService.getAuthenticatedOrFail(username, password);accessor.setUser(user);}return message;}
}请注意preSend() 必须返回 UsernamePasswordAuthenticationTokenSpring 安全链中会对此进行测试。如果UsernamePasswordAuthenticationToken构建没有通过GrantedAuthority则身份验证将失败因为没有授予权限的构造函数自动设置authenticated false 这是一个重要的细节在 spring-security 中没有记录。 最后再创建两个类来分别处理授权和身份验证。
Configuration
Order(Ordered.HIGHEST_PRECEDENCE 99)
public class WebSocketAuthenticationSecurityConfig extends WebSocketMessageBrokerConfigurer {Injectprivate AuthChannelInterceptorAdapter authChannelInterceptorAdapter;Overridepublic void registerStompEndpoints(final StompEndpointRegistry registry) {// 这里不用给任何东西}Overridepublic void configureClientInboundChannel(final ChannelRegistration registration) {registration.setInterceptors(authChannelInterceptorAdapter);}}请注意这Order是至关重要的它允许我们的拦截器首先在安全链中注册。 Configuration
public class WebSocketAuthorizationSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {Overrideprotected void configureInbound(final MessageSecurityMetadataSourceRegistry messages) {// 添加自己的映射messages.anyMessage().authenticated();}// 这里请自己按需求修改Overrideprotected boolean sameOriginDisabled() {return true;}
}之后编写客户端进行连接我们就可以这样指定客户端进行消息的发送。 MessageMapping(/greeting)public void greetingReturn(Payload Object ojd){simpMessagingTemplate.convertAndSendToUser(username,/topic/greeting,ojd);}