shiro使用reids缓存session 踩坑 (已解决)

shiro使用reids缓存session 踩坑

方案一: shiro-redis插件[未成功]

方案二: 修改sessionDao,手动实现存储读取 [成功]

shiro配置

@Configuration
public class ShiroConfig {

    @Value("${spring.redis.shiro.host}")
    private String host;
    @Value("${spring.redis.shiro.port}")
    private int port;
    @Value("${spring.redis.shiro.timeout}")
    private int timeout;
    @Value("${spring.redis.shiro.password}")
    private String password;

	// 这个redisUtil是json格式的存储读取
    @Resource
    RedisUtil redisUtil;
    // 这个是btye格式的存储和读取,由于session格式成json一直报序列化错误,只能存成byte
    @Resource
    RedisSessionUtil redisSessionUtil;

    @Value(value = "${mcinema.auth.session-token-key}")
    private String SESSION_TOKEN_KEY;
    @Value(value = "${mcinema.redis-key.session-admin}")
    private String sessionRoot;

    // 注册shiroFilterFactoryBean
    @Bean(name = "shiroFilterFactoryBean")
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        bean.setSecurityManager(securityManager);
        Map<String, String> filter = new LinkedHashMap<>();
        // 设置拦截器
        bean.setFilterChainDefinitionMap(filter);
        return bean;
    }
     //注册DefaultWebSecurityManager
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager adminWebSecurityManager(
            AdminRealm adminRealm,
            AdminSessionManagement sessionManager) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(adminRealm); // 设置Realm对象
        securityManager.setSessionManager(sessionManager); // 设置session管理
        return securityManager;
    }

  	//注册Realm
    @Bean(name = "adminRealm")
    public AdminRealm adminRealm() {
        return new AdminRealm();
    }

    // 注册sessionManager
    @Bean(name = "sessionManager")
    public AdminSessionManagement adminSessionManagement(AdminSessionDAO adminSessionDAO) {
        AdminSessionManagement sessionManagement = new AdminSessionManagement(SESSION_TOKEN_KEY);
        sessionManagement.setSessionDAO(adminSessionDAO);
        return sessionManagement;
    }

    @Bean(name="adminSessionDAO")
    public AdminSessionDAO adminSessionDAO(){
        return new AdminSessionDAO(redisSessionUtil,sessionRoot);
    }
    

    // 开启注解功能
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public static DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator();
        creator.setProxyTargetClass(true);
        return creator;
    }

    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }
}

redis template配置

    @Bean(name = "redisSessionTemplate")
    @SuppressWarnings("all")
    public RedisTemplate<String, Object> redisSessionTemplate(RedisConnectionFactory factory) {
        RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
        template.setConnectionFactory(factory);

        MyRedisSerializer myRedisSerializer = new MyRedisSerializer();

        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        template.setKeySerializer(stringRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);
        template.setValueSerializer(myRedisSerializer);
        template.setHashValueSerializer(myRedisSerializer);
        template.setDefaultSerializer(myRedisSerializer);
        template.afterPropertiesSet();

        return template;
    }

自定义序列化方式 这个更shiro-redis插件配置的ObjectSerialize差不多,不知道为什么我用那个还是会报错

public class MyRedisSerializer implements RedisSerializer<Object> {
 
 
    @Override
    public byte[] serialize(Object o) throws SerializationException {
        ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
        ObjectOutputStream objOut;
        try {
            objOut = new ObjectOutputStream(byteOut);
            objOut.writeObject(o);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return byteOut.toByteArray();
    }
 
    @Override
    public Object deserialize(byte[] bytes) throws SerializationException {
        if(bytes == null) return null;
        ByteArrayInputStream byteIn = new ByteArrayInputStream(bytes);
        ObjectInputStream objIn;
        Object obj;
        try {
            objIn = new ObjectInputStream(byteIn);
            obj =objIn.readObject();
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
            return null;
        }
        return obj;
    }
 
}

redisUtil就不贴了,都差不多,你改下操作的template就行了

看运行发现读取次数过多,网上的办法是将获取的session存储到request里
自定义的sessionManager 继承 defaultSessionManage 覆写 retrieveSession方法

这个是网上抄的,水平有限,就没改了,能用就行,发现问题评论告诉我

public class AdminSessionManagement extends DefaultWebSessionManager{
    @Override
    protected Session retrieveSession(SessionKey sessionKey) throws UnknownSessionException {
        Serializable sessionId = getSessionId(sessionKey);
        if (sessionId == null) {
            log.debug("Unable to resolve session ID from SessionKey [{}].  Returning null to indicate a "
                    + "session could not be found.", sessionKey);
            return null;
        }
        // ***************Add By Goma****************
        ServletRequest request = null;
        if (sessionKey instanceof WebSessionKey) {
            request = ((WebSessionKey) sessionKey).getServletRequest();
        }

        if (request != null) {
            Object s = request.getAttribute(sessionId.toString());
            if (s != null) {
                return (Session) s;
            }
        }
        // ***************Add By Goma****************

        Session s = retrieveSessionFromDataSource(sessionId);
        if (s == null) {
            // session ID was provided, meaning one is expected to be found, but
            // we couldn't find one:
            String msg = "Could not find session with ID [" + sessionId + "]";
            throw new UnknownSessionException(msg);
        }
        // ***************Add By Goma****************
        if (request != null) {
            request.setAttribute(sessionId.toString(), s);
        }
        // ***************Add By Goma****************
        return s;
    }
	// session的键值
    private final String SESSION_TOKEN_KEY;
    // session的来源
    private static final String SESSION_SOURCE = "request header";

    public AdminSessionManagement(String session_token_key) {
        this.SESSION_TOKEN_KEY = session_token_key;
    }

    @Override
    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
        String id = WebUtils.toHttp(request).getHeader(SESSION_TOKEN_KEY);
        if (DataUtil.checkEmpty(id)) {
            WebUtils.toHttp(response).setHeader(SESSION_TOKEN_KEY, id);
            // 设置session来源
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, SESSION_SOURCE);
            // 设置sessionId
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
            // 设置标记此sessionId为有效
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
            return id;
        }
        return super.getSessionId(request, response);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Shiro-Redis 是一个用于在 Shiro 实现 Session 共享的插件,它使用 Redis 作为数据存储和缓存,以实现分布式环境下的 Session 共享。 要实现 Shiro-RedisSession 共享,你需要进行以下步骤: 1. 引入 Shiro-Redis 插件依赖:在项目的 Maven 或 Gradle 配置文件添加 Shiro-Redis 依赖。 2. 配置 Redis 连接信息:在项目的配置文件配置 Redis 的连接信息,包括主机名、端口号、密码等。 3. 配置 RedisSessionDAO:在 Shiro 的配置文件配置 RedisSessionDAO,指定使用 Redis 作为 Session 存储和缓存的实现。可以设置过期时间、前缀等参数。 4. 配置 Session Manager:在 Shiro 的配置文件配置 Session Manager,指定使用自定义的 RedisSessionManager 作为 Session 的管理器。同时,需要将之前配置的 RedisSessionDAO 设置给 RedisSessionManager。 5. 配置 SecurityManager:在 Shiro 的配置文件配置 SecurityManager,指定使用自定义的 RedisSessionManager 作为 Session 管理器。同时,需要将之前配置的 RedisSessionDAO 设置给 RedisSessionManager。 6. 配置 Filter Chain:在 Shiro 的配置文件配置 Filter Chain,将自定义的 RedisSessionManager 添加到 Filter Chain ,以便对请求进行 Session 管理。 通过以上步骤配置完成后,Shiro 将会使用 Redis 进行 Session 的存储和缓存,从而实现 Session 的共享。在分布式环境,不同应用节点之间可以通过 Redis 共享 Session 数据,从而实现用户的登录状态和会话信息的共享。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值