shiro整合redis实现session共享

司空赞
2023-12-01

shiro整合redis实现session共享
       通过nginx实现负载均衡后,同一客户端的请求会被分配到不同的服务器,减少了单机模式下服务器的压力,但同时也带来了问题,用户第一次访问服务器后,session保存在了一台服务器,之后再次请求,若nginx将请求分配到其他服务器,其他服务器根据cookie中的sessionId找不到对应的session,用户就需要重新登录。
       shiro整合redis,将session保存redis中,这样用户每次请求都到redis中查,如果根据sessionId可以查到session,说明用户已登录。单机模式下,sessionDao的实现类MemorySessionDAO是将session保存到了并发容器ConcurrentMap中,也就是保存在内容里,所以无法实现服务器间的共享。
       上一篇博客写了MemorySessionDAO的实现,基于它我们通过继承AbstractSessionDAO并重写CRUD完成session在redis中的操作。
1.引入redis maven依赖

<!-- 1、java连接Redis的jar包,也就是使用jedis -->
        <dependency>
            <groupId>redis.clients</groupId>
            <artifactId>jedis</artifactId>
            <version>2.4.2</version>
        </dependency>

        <!-- 2、spring整合Redis的jar包 -->
        <dependency>
            <groupId>org.springframework.data</groupId>
            <artifactId>spring-data-redis</artifactId>
            <version>1.4.2.RELEASE</version>
        </dependency>

2.redis配置类

package com.ssm.service;


import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.JedisPoolConfig;

@Configuration
public class JedisPoolConfiguration {
    /**
     * jedis连接池配置
     * @return
     * @Bean  加载后,方法返回的对象作为bean,被放在IOC容器里
     */
    @Bean
    /*@ConfigurationProperties(prefix = "jedisPool")*/
    public JedisPoolConfig jedisPoolConfig(){
        System.out.println("配置类执行了");
        //采用默认的连接池配置
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        return jedisPoolConfig;
    }

    /**
     * 连接工厂配置信息,需要注入连接池配置信息
     * @param jedisPoolConfig
     * @return
     */
    @Bean
    public JedisConnectionFactory jedisConnectionFactory(JedisPoolConfig jedisPoolConfig){
        JedisConnectionFactory jedisConnectionFactory = new JedisConnectionFactory();
        jedisConnectionFactory.setPoolConfig(jedisPoolConfig);
        jedisConnectionFactory.setHostName("192.168.1.128");
        jedisConnectionFactory.setPort(6379);
        //jedisConnectionFactory.setDatabase(0);  指定使用redis的哪个库,16个数据库,默认选择0
        return jedisConnectionFactory;
    }

    /**
     * 操作redis方法的对象,需要注入连接工厂,封装了操作redis的方法
     * @param jedisConnectionFactory
     * @return
     */
    @Bean
    public RedisTemplate<String,Object> redisTemplate(JedisConnectionFactory jedisConnectionFactory){
        RedisTemplate<String,Object> redisTemplate = new RedisTemplate<>();
        redisTemplate.setConnectionFactory(jedisConnectionFactory);
        //指定key、value的序列化方式
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        redisTemplate.setValueSerializer(new JdkSerializationRedisSerializer());
        return  redisTemplate;
    }

}

3.重写sessionDao

package com.ssm.util;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;
import org.apache.shiro.session.mgt.eis.AbstractSessionDAO;
import org.apache.shiro.session.mgt.eis.MemorySessionDAO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;

import javax.annotation.Resource;
import java.io.Serializable;
import java.util.Collection;
import java.util.concurrent.TimeUnit;

public class SessionDao extends AbstractSessionDAO {
    //key有效期设置
    public static final int EXPIRE_TIME = 300;

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Override
    protected Serializable doCreate(Session session) {
        //根据session生成sessionId
        Serializable sessionId = this.generateSessionId(session);
        //将session与sessionId进行绑定
        this.assignSessionId(session, sessionId);
        //将session保存在redis中,key-sessionId;value-session
        redisTemplate.opsForValue().set(sessionId.toString(),session,EXPIRE_TIME, TimeUnit.SECONDS);
        return  sessionId;
    }

    @Override
    public void update(Session session) throws UnknownSessionException {
       //更新session的本质就是重新set一次
        redisTemplate.opsForValue().set(session.getId().toString(),session,EXPIRE_TIME, TimeUnit.SECONDS);
    }

    @Override
    public void delete(Session session) {
        //从redis中移除key
        redisTemplate.delete(session.getId().toString());
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
        //通过sessionId获取session,用户登录后发送请求,先读,如果获取到session,则再调用update()方法更新session
        Session session = (Session) redisTemplate.opsForValue().get(sessionId.toString());
        return session;
    }

     /**
     * 可用来实现统计在线人数等功能
     * @return
     */
    @Override
    public Collection<Session> getActiveSessions() {
        return null;
    }
 类似资料: