Spring中的Websocket身份验证和授权

这篇具有很好参考价值的文章主要介绍了Spring中的Websocket身份验证和授权。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。

一、需要了解的事项

  • http和WebSocket的安全链和安全配置是完全独立的。
  • SpringAuthenticationProvider根本不参与 Websocket 身份验证。
  • 将要给出的示例中,身份验证不会发生在 HTTP 协商端点上,因为 JavaScript STOMP(websocket)库不会随 HTTP 请求一起发送必要的身份验证标头。
  • 一旦在 CONNECT 请求上设置,用户( simpUser) 将被存储在 websocket 会话中,并且以后的消息将不再需要进行身份验证。

二、依赖

<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 配置

3.1 、简单的消息代理

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketConfig extends WebSocketMessageBrokerConfigurer {
    @Override
    public void configureMessageBroker(final MessageBrokerRegistry config) {
        config.enableSimpleBroker("/queue/topic");
        config.setApplicationDestinationPrefixes("/app");
    }

    @Override
    public void registerStompEndpoints(final StompEndpointRegistry registry) {
        registry.addEndpoint("stomp"); 
        setAllowedOrigins("*")
    }
}

3.2 、Spring安全配置

由于 Stomp 协议依赖于第一个 HTTP 请求,因此需要授权对 stomp 握手端点的 HTTP 调用。

@Configuration
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(final HttpSecurity http) throws Exception
        http.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;

    @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) {
        // 这里不用给任何东西
    }

    @Override
    public void configureClientInboundChannel(final ChannelRegistration registration) {
        registration.setInterceptors(authChannelInterceptorAdapter);
    }

}

请注意:这@Order是至关重要的,它允许我们的拦截器首先在安全链中注册。

@Configuration
public class WebSocketAuthorizationSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
    @Override
    protected void configureInbound(final MessageSecurityMetadataSourceRegistry messages) {
        // 添加自己的映射
        messages.anyMessage().authenticated();
    }

    // 这里请自己按需求修改
    @Override
    protected boolean sameOriginDisabled() {
        return true;
    }
}

之后编写客户端进行连接,我们就可以这样指定客户端进行消息的发送。文章来源地址https://www.toymoban.com/news/detail-642744.html

    @MessageMapping("/greeting")
    public void greetingReturn(@Payload Object ojd){
         simpMessagingTemplate.convertAndSendToUser(username,"/topic/greeting",ojd);
    }

到了这里,关于Spring中的Websocket身份验证和授权的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring - Security 之 Servlet身份验证架构

    这个讨论是对之前文章的扩展,用于描述Spring Security在Servlet身份验证中使用的主要架构组件。 组件 描述 SecurityContextHolder SecurityContextHolder是Spring Security存储已认证用户详细信息的位置。 SecurityContext 从SecurityContextHolder获取,包含当前认证用户的认证信息。 Authentication 可以是

    2024年01月23日
    浏览(38)
  • Spring Security 身份验证的基本类/架构

    目录 1、SecurityContextHolder 核心类 2、SecurityContext 接口 3、Authentication 用户认证信息接口 4、GrantedAuthority 拥有权限接口 5、AuthenticationManager 身份认证管理器接口 6、ProviderManager 身份认证管理器的实现 7、AuthenticationProvider 特定类型的身份验证接口 8、AuthenticationEntryPoint 身份验证

    2024年02月16日
    浏览(38)
  • Spring Security实现用户身份验证及权限管理

    Spring Security是Spring生态的一个成员,提供了一套Web应用安全性的完整解决方案。 Spring Security 旨在以一种自包含的方式进行操作,因此你不需要在 Java 运行时环境中放置任何特殊的配置文件。这种设计使部署极为方便,因为可以将目标 工件 (无论是 JAR还是WAR)从一个系统复

    2024年02月05日
    浏览(36)
  • Spring boot Websocket 添加授权校验(校验Header)

            最近需要用到websocket,并且确认是在登录成功的情况下才能连接,看了下,websocket 5.8以上已经支持校验了,但是由于我项目是spring boot 2.7.9,为了兼容,只能考虑通过在websocket 的header中带上验证信息,进行校验,详细如下 1.首先往spring boot pom 内加入 websocket的依赖

    2024年02月07日
    浏览(30)
  • 禁用AMQP配置中的明文身份验证机制(包含Springboot结果测试+踩坑)

    最近公司内网部署RabbitMQ服务器,部署上测试后安全部门扫描到MQ服务器有一个漏洞【禁用AMQP配置中的明文身份验证机制】。本文记录解决该漏洞的过程和方法,以及遇到的问题 主要步骤为: 在服务器生成所需的两对密钥和CA证书,然后将CA、服务器公私钥放到Rabbit目录下并

    2024年02月14日
    浏览(33)
  • Blazor入门100天 : 身份验证和授权 (1) - 建立带身份验证工程

    目录 建立默认带身份验证 Blazor 程序 角色/组件/特性/过程逻辑 DB 改 Sqlite 将自定义字段添加到用户表 脚手架拉取IDS文件,本地化资源 freesql 生成实体类,freesql 管理ids数据表 初始化 Roles,freesql 外键 = 导航属性 完善 freesql 和 bb 特性 知识点 Microsoft.AspNetCore.Identity EntityFramework Sql

    2024年02月05日
    浏览(73)
  • .netcore grpc身份验证和授权

    权限认证这里使用IdentityServer4配合JWT进行认证 通过AddAuthentication和AddAuthorization方法进行鉴权授权注入;通过UseAuthentication和UseAuthorization启用鉴权授权 增加授权策略处理 使用密码模式,及简易内存处理 生成token带入grpc的metadata进行传递 服务端对应的方法标记特性[Authorize]进行

    2024年02月12日
    浏览(37)
  • Welcome to YARP - 5.身份验证和授权

    Welcome to YARP - 1.认识YARP并搭建反向代理服务 Welcome to YARP - 2.配置功能 2.1 - 配置文件(Configuration Files) 2.2 - 配置提供者(Configuration Providers) 2.3 - 配置过滤器(Configuration Filters) Welcome to YARP - 3.负载均衡 Welcome to YARP - 4.限流 Welcome to YARP - 5.身份验证和授权 Welcome to YARP - 6.压缩

    2024年02月05日
    浏览(47)
  • 系列六、Spring Security中的认证 & 授权 & 角色继承

            关于Spring Security中的授权,请参考【系列一、认证 授权】,这里不再赘述。 1.4.1、admin登录 (一) 登录 (二) 访问sayHi(登录就可以访问) (三)访问/admin/helloWorld接口(需要拥有admin角色)  (四)访问/dba/helloWorld接口(需要拥有dba角色,admin自动继承dba角色)

    2024年02月01日
    浏览(35)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包