Java – Spring中的Websocket身份验证和授权
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了Java – Spring中的Websocket身份验证和授权,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含6532字,纯文字阅读大概需要10分钟。
内容图文
![Java – Spring中的Websocket身份验证和授权](/upload/InfoBanner/zyjiaocheng/711/01ae8156189244c9a36cc05aa7cb9f59.jpg)
我一直在努力用Spring-Security正确实现Stomp(websocket)身份验证和授权.对于后代,我会回答我自己的问题,提供指导.
问题
Spring WebSocket文档(用于身份验证)看起来不清楚ATM(恕我直言).我无法理解如何正确处理身份验证和授权.
我想要的是
>使用登录名/密码验证用户.
>防止匿名用户通过WebSocket进行连接.
>添加授权层(用户,管理员,…).
>校长可以使用校长.
我不想要的
>在HTTP协商端点上进行身份验证(因为大多数JavaScript库不会与HTTP协商调用一起发送身份验证标头).
解决方法:
如上所述,文档(ATM)尚不清楚,直到Spring提供了一些清晰的文档,这里有一个样板,可以帮助您节省两天时间,试图了解安全链正在做什么.
Rob-Leggett是一个非常好的尝试,但他是forking some Springs class,我觉得这样做并不舒服.
要知道的事情:
> http和WebSocket的安全链和安全配置是完全独立的.
> Spring AuthenticationProvider在Websocket身份验证中完全不参与.
> HTTP协商端点上不会发生身份验证,因为JavaScripts STOMP(websocket)都没有发送身份验证标头和HTTP请求.
>一旦在CONNECT请求上设置,用户(simpUser)将存储在websocket会话中,并且不再需要对其他消息进行身份验证.
Maven deps
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-websocket</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-messaging</artifactId>
</dependency>
WebSocket配置
下面的配置注册一个简单的消息代理(请注意,它与身份验证和授权无关).
@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends WebSocketMessageBrokerConfigurer {
@Override
public void configureMessageBroker(final MessageBrokerRegistry config) {
// These are endpoints the client can subscribes to.
config.enableSimpleBroker("/queue/topic");
// Message received with one of those below destinationPrefixes will be automatically router to controllers @MessageMapping
config.setApplicationDestinationPrefixes("/app");
}
@Override
public void registerStompEndpoints(final StompEndpointRegistry registry) {
// Handshake endpoint
registry.addEndpoint("stomp"); // If you want to you can chain setAllowedOrigins("*")
}
}
Spring安全配置
由于Stomp协议依赖于第一个HTTP请求,因此我们需要授权对我们的stomp握手端点进行HTTP调用.
@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(final HttpSecurity http) throws Exception {
// This is not for websocket authorization, and this should most likely not be altered.
http
.httpBasic().disable()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
.authorizeRequests().antMatchers("/stomp").permitAll()
.anyRequest().denyAll();
}
}
然后我们将创建一个负责验证用户的服务.
@Component
public class WebSocketAuthenticatorService {
// This method MUST return a UsernamePasswordAuthenticationToken instance, the spring security chain is testing it with 'instanceof' later on. So don't use a subclass of it or any other class
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.");
}
// Add your own logic for retrieving user in fetchUserFromDb()
if (fetchUserFromDb(username, password) == null) {
throw new BadCredentialsException("Bad credentials for user " + username);
}
// null credentials, we do not pass the password along
return new UsernamePasswordAuthenticationToken(
username,
null,
Collections.singleton((GrantedAuthority) () -> "USER") // MUST provide at least one role
);
}
}
注意:UsernamePasswordAuthenticationToken必须有GrantedAuthorities,如果你使用另一个构造函数,Spring将自动设置isAuthenticated = false.
几乎在那里,现在我们需要创建一个Interceptor,它将设置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;
@Inject
public AuthChannelInterceptorAdapter(final WebSocketAuthenticatorService webSocketAuthenticatorService) {
this.webSocketAuthenticatorService = webSocketAuthenticatorService;
}
@Override
public 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()必须返回一个UsernamePasswordAuthenticationToken,这是spring安全链中的另一个元素测试.
请注意:如果构建了UsernamePasswordAuthenticationToken而未传递GrantedAuthority,则身份验证将失败,因为没有授予权限的构造函数自动设置authenticated = false这是一个重要的详细信息,未在spring-security中记录.
最后再创建两个类来分别处理授权和认证.
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE + 99)
public class WebSocketAuthenticationSecurityConfig extends WebSocketMessageBrokerConfigurer {
@Inject
private AuthChannelInterceptorAdapter authChannelInterceptorAdapter;
@Override
public void registerStompEndpoints(final StompEndpointRegistry registry) {
// Endpoints are already registered on WebSocketConfig, no need to add more.
}
@Override
public void configureClientInboundChannel(final ChannelRegistration registration) {
registration.setInterceptors(authChannelInterceptorAdapter);
}
}
注意:@Order是CRUCIAL不要忘记它,它允许我们的拦截器首先在安全链中注册.
@Configuration
public class WebSocketAuthorizationSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
@Override
protected void configureInbound(final MessageSecurityMetadataSourceRegistry messages) {
// You can customize your authorization mapping here.
messages.anyMessage().authenticated();
}
// TODO: For test purpose (and simplicity) i disabled CSRF, but you should re-enable this and provide a CRSF endpoint.
@Override
protected boolean sameOriginDisabled() {
return true;
}
}
内容总结
以上是互联网集市为您收集整理的Java – Spring中的Websocket身份验证和授权全部内容,希望文章能够帮你解决Java – Spring中的Websocket身份验证和授权所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。