Redis的应用の使用SpringSession实现WebSocket的用户身份认证

之前有过两篇博文是有关WebSocket身份认证的

WebSocket的用户身份认证

关于使用浏览器与PostMan测试springSession每次返回的x-auto-token不一致的问题解决

当时是处于一个探索的环节,现在我们将使用SpringSession、Redis,通过Header认证来实现WebSocket中用户身份的认证。

注意:为了简化文章,我们假设用户已经是通过登录并且获得x-auth-token值的。下文中不会给出的内容有:redis的配置、

首先看下我们的Redis设置,里面涉及到了一个RedisTemplate类的注册:

@Configuration
@EnableCaching
public class RedisConfig extends CachingConfigurerSupport {
    @Bean
    <T> RedisTemplate<String, User> redisTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, User> redisTemplate = new RedisTemplate<>();
        System.out.println("加载redis配置");

        JdkSerializationRedisSerializer jdkSerializationRedisSerializer = new JdkSerializationRedisSerializer(User.class.getClassLoader());
        
        redisTemplate.setValueSerializer(jdkSerializationRedisSerializer);
        redisTemplate.setHashValueSerializer(jdkSerializationRedisSerializer);
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setHashKeySerializer(new StringRedisSerializer());
        redisTemplate.setConnectionFactory(factory);
        redisTemplate.setEnableTransactionSupport(true);
        return redisTemplate;
    }
}

通过RedisTemplate的注册,我们可以使用redisTemplate这个实例来操作Redis数据库。并且我们使用的是jdk反序列化(因为SpringSession是使用jdk序列化的,我们需要使用该实例来获得SpringSession存放在Redis中的数据,使用其他反序列化会导致乱码)。

WebSocket的配置:

@Configuration
@EnableWebSocket
public class WebSocketConfig implements WebSocketConfigurer {
    private int loss_connect_time = 0;
    @Autowired
    private WebSocketHandler handler;
    @Autowired
    private WebSocketInterceptor webSocketInterceptor;

    @Override
    public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
        registry.addHandler(handler, "/message").addInterceptors(webSocketInterceptor).setAllowedOrigins("*");
        registry.addHandler(handler, "/sockjs/message").addInterceptors(webSocketInterceptor).setAllowedOrigins("*").withSockJS();
    }
}

此处的WebSocketHandler是用以处理WebSocket连接的处理器,我们将在这里进行WebSocket数据的接收处理及转发,而webSocketInterceptor则是一个Websocket连接的拦截器,通过该拦截器我们可以对用户的身份进行认证,决定其是否能够建立WebSocket连接。

registerWebSocketHandlers中我们注册了WebSocket连接的接口,使用ws://localhost:port/message就可以建立WebSocket连接了。

首先让我们看一下webSocketInterceptor

@Service
@Slf4j
public class WebSocketInterceptor implements HandshakeInterceptor {

    @Resource
    private RedisTemplate<String, User> redisTemplate;

    @Override
    public boolean beforeHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse,
                                   WebSocketHandler webSocketHandler, Map<String, Object> map) {
        log.info("webSocket握手请求...");
        if (serverHttpRequest instanceof ServletServerHttpRequest) {
            ServletServerHttpRequest servletRequest = (ServletServerHttpRequest) serverHttpRequest;
            // 取得x-auth-token参数
            String token = servletRequest.getServletRequest().getHeader("x-auth-token");
            log.info("websocket连接令牌" + token);

            if (null != token && !token.equals("")) {
                // 利用SpringSession在Redis数据库中的存放方式读取user对象
                User user = (User) redisTemplate.opsForHash().get("spring:session:sessions:" + token, "sessionAttr:user");

                // 此处可以进行用户权限的判定,从而决定是否允许建立WebSocket连接
                if (null != user) {
                    // 判断user对象
                    log.info("user用户:" + user);
                    // 将user对象于某一唯一标志绑定放入map中
                    // 我们可以在后续的WebSocketHandler操作中使用到user的值
                    map.put(serverHttpRequest.getRemoteAddress().toString(), user);
                    return true;
                }
            }
        }
        return false;
    }

    @Override
    public void afterHandshake(ServerHttpRequest serverHttpRequest, ServerHttpResponse serverHttpResponse,
                               WebSocketHandler webSocketHandler, Exception e) {
        log.info("webSocket握手结束...");
    }
}

beforeHandshake()中返回true即为通过验证,允许建立连接,反之不允许。

在实际操作中,我们会与接口ws://localhost:port/message?x-auth-token=8ea455a8-7f61-45af-ae20-e5627ee89f15建立连接,传入的x-auth-token即为SpringSession的唯一标志,并且对应着Redis数据库中spring:session:sessions:后续的一串字母。有了x-auth-token

到了这里还是要讲一下x-auth-token是怎么来的。在SpringSession的设置中:

@Configuration
@EnableRedisHttpSession(maxInactiveIntervalInSeconds = 1801)
public class HttpSessionConfig {
    @Bean
    public HeaderHttpSessionIdResolver httpSessionStrategy() {
        return new HeaderHttpSessionIdResolver("x-auth-token");
    }
}

通过HeaderHttpSessionIdResolver可以设置SpringSession为Header认证策略,同时设置其指定的头部信息为x-auth-token。这样,当用户每次操作新的Session时,都会使用x-auth-token返回一个新的Session标志,同时,我们设置头部信息x-auth-token=asd就可以拿到相对于的Session。这种方法避免了用户禁用Cookie导致Session不可用的情况的发生。

到了此处就已经是WebSocket的用户认证的整个过程了,不过大家可能还记得我们在WebSocketInterceptor

中往map存入用户信息的操作吧。那么我们接下来我们就可以在WebSocketHandler中使用用户信息了:

@Service
@Slf4j
public class MyWebSocketHandler implements WebSocketHandler {

    @Override
    public void afterConnectionEstablished(WebSocketSession webSocketSession) throws Exception {

        log.info("成功建立连接");
    }

    @Override
    public void handleMessage(WebSocketSession webSocketSession,
                              WebSocketMessage<?> webSocketMessage) throws Exception {
        String message = webSocketMessage.getPayload().toString();
        log.info("接收信息 >> {}", message);

		// 此处拿到刚才存放的用户信息
		User user = (User) webSocketSession.getAttributes()            .get(String.valueOf(webSocketSession.getRemoteAddress()));
    }

    @Override
    public void handleTransportError(WebSocketSession webSocketSession,
                                     Throwable throwable) throws Exception {
        log.info("{}连接出现异常", webSocketSession.getId());
    }

    @Override
    public void afterConnectionClosed(WebSocketSession webSocketSession,
                                      CloseStatus closeStatus) throws Exception {
        log.info("Socket会话结束,即将移除socket");
    }

    @Override
    public boolean supportsPartialMessages() {
        return false;
    }
}

总的来说WebSocket的身份认证还是建立在Http的身份认证之上的,通过Http用户进行登陆后存储用户的基本信息,此时我们就可以通过x-auth-token取得用户的Session,对Session里面的数据进行验证,判断是否有权限建立WebSocket连接,若通过之后我们又可以通过Map数据的存放,在WebSocketHandler中也可以使用用户的信息。这样就能够跨越Http与WebSocket之间的阻碍了。

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 要使用Redis实现Spring Boot应用程序的会话共享,您需要执行以下步骤: 1. 添加Redis依赖项 在您的Spring Boot项目中添加spring-boot-starter-data-redis依赖项,这将为您提供Redis客户端和Spring Session依赖项。 2. 配置Redis 在application.properties文件中添加Redis配置,包括Redis服务器的主机名、端口和密码。 3. 启用Spring SessionSpring Boot应用程序中启用Spring Session,您需要将@EnabaleRedisHttpSession注释添加到Spring Boot主应用程序类上。 4. 配置会话超时 您可以在application.properties文件中设置会话超时时间,例如:spring.session.timeout=30m。 5. 测试 最后,您可以测试您的Spring Boot应用程序是否正在使用Redis进行会话共享,通过多个实例运行应用程序,并在每个实例中访问同一URL并查看结果是否相同。 通过这些步骤,您应该能够在Spring Boot应用程序中使用Redis进行会话共享。 ### 回答2: 在Spring Boot中使用Redis实现session共享可以通过以下步骤实现: 1. 首先,确保在pom.xml文件中添加以下依赖项以在Spring Boot中使用Redis: ```xml <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-data-redis</artifactId> </dependency> ``` 2. 在application.properties文件中配置Redis连接信息: ```properties spring.redis.host=your-redis-host spring.redis.port=your-redis-port spring.redis.password=your-redis-password ``` 3. 创建一个配置类(如RedisConfig.java),用于配置与Redis的连接以及序列化的设置: ```java import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.data.redis.connection.RedisConnectionFactory; import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer; import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.session.data.redis.config.annotation.web.http.EnableRedisHttpSession; @Configuration @EnableRedisHttpSession(maxInactiveIntervalInSeconds = 86400) // 设置session的有效时间,单位为秒 public class RedisConfig { @Bean public RedisSerializer<Object> redisSerializer() { // 使用JSON序列化器,存储到Redis中的Session以JSON格式保存,方便阅读 return new GenericJackson2JsonRedisSerializer(); } @Bean public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory) { RedisTemplate<String, Object> template = new RedisTemplate<>(); template.setConnectionFactory(redisConnectionFactory); // 设置key和value的序列化器 template.setKeySerializer(new StringRedisSerializer()); template.setValueSerializer(redisSerializer()); template.setHashKeySerializer(new StringRedisSerializer()); template.setHashValueSerializer(redisSerializer()); return template; } } ``` 4. 在需要使用session的地方注入`HttpSession`,并使用它来获取、设置和删除session中的属性: ```java import javax.servlet.http.HttpSession; // 注入HttpSession @Autowired private HttpSession session; // 获取session中的属性 Object attributeValue = session.getAttribute("attributeName"); // 设置session中的属性 session.setAttribute("attributeName", attributeValue); // 删除session中的属性 session.removeAttribute("attributeName"); ``` 这样,通过以上步骤,就可以在Spring Boot中使用Redis实现session共享了。注意,由于Redis是内存数据库,需要设置session的有效时间以避免占用过多的内存资源。 ### 回答3: 使用Spring Boot实现Session共享的方法有两种:使用Spring Session使用RedisTemplate。 第一种方法是使用Spring Session实现Session共享。Spring Session是一个用于在分布式环境下管理SessionSpring项目,它提供了一种基于SpringSession管理解决方案。要使用Spring Session,需要在pom.xml文件中添加相关依赖,然后在Spring Boot配置类中加上@EnableRedisHttpSession注解,配置Redis连接信息。这样,Spring Session会将Session信息存储到Redis中,实现Session的共享。 第二种方法是使用RedisTemplate来实现Session共享。RedisTemplate是Spring Data Redis提供的一个用于操作Redis的模板类,可以方便地进行Redis的读写操作。要使用RedisTemplate实现Session共享,首先需要在pom.xml文件中添加相关依赖,然后在Spring Boot配置类中创建一个RedisConnectionFactory实例,并将其注入到RedisTemplate中。通过RedisTemplate,可以将Session信息存储到Redis中,并实现Session的共享。 无论是使用Spring Session还是使用RedisTemplate,都需要在Spring Boot配置文件中配置Redis连接信息,包括Redis服务器的IP地址、端口号和密码(如果有)。此外,还可以配置Redis的连接池参数,以提高性能和并发能力。 总结起来,要使用Spring Boot实现RedisSession共享,可以使用Spring SessionRedisTemplate两种方式。通过配置相关依赖和连接信息,将Session信息存储到Redis中,实现Session的共享。这样,在分布式环境下,不同的应用实例之间就能够共享Session,并实现会话的跨应用访问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值