首页 > 数据库 >Shiro 框架中如何更新Redis的超时登录时间?

Shiro 框架中如何更新Redis的超时登录时间?

时间:2023-12-23 23:36:09浏览次数:45  
标签:Session 过期 Redis 会话 session 时间 超时 Shiro


在Shiro框架中,可以通过实现SessionDAO接口来将会话信息保存到Redis中,并且可以通过实现SessionValidationScheduler接口来定期检查会话是否过期。因此,要更新Redis中的超时登录时间,可以按照以下步骤进行操作:

  • 实现SessionDAO接口,将会话信息保存到Redis中。在实现SessionDAO接口时,可以使用Redis的EXPIRE命令来设置会话的过期时间。具体的实现方式取决于你使用的Redis客户端库。
  • 实现SessionValidationScheduler接口,定期检查会话是否过期。在实现SessionValidationScheduler接口时,可以使用Redis的TTL命令来获取会话的剩余过期时间,然后根据剩余过期时间来判断会话是否过期。如果会话已经过期,则可以将其从Redis中删除。
public class RedisSessionDAO implements SessionDAO {
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public void update(Session session) throws UnknownSessionException {
        // 将会话信息保存到Redis中
        redisTemplate.opsForValue().set(session.getId(), session);
        // 设置会话的过期时间
        redisTemplate.expire(session.getId(), session.getTimeout(), TimeUnit.MILLISECONDS);
    }
}

public class RedisSessionValidationScheduler implements SessionValidationScheduler {
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public void enableSessionValidation() {
        // 定期检查会话是否过期
        while (true) {
            Set<String> sessionIds = redisTemplate.keys("shiro:session:*");
            for (String sessionId : sessionIds) {
                Long ttl = redisTemplate.getExpire(sessionId, TimeUnit.SECONDS);
                if (ttl != null && ttl <= 0) {
                    redisTemplate.delete(sessionId);
                }
            }
            try {
                Thread.sleep(60000); // 每分钟检查一次
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

SecurityUtils.getSubject().getSession().setTimeout(TimeValue);里边设置默认的Session过期时间,但是redis中 redisTemplate.opsForValue().set(SESSION_PREFIX+session.getId(),session,DEFAULT_TIME_OUT, TimeUnit.MINUTES);中的DEFAULT_TIME_OUT如何与TimeValue同步更新?

在Shiro框架中,SecurityUtils.getSubject().getSession().setTimeout(TimeValue)方法用于设置当前用户的会话过期时间,而redisTemplate.opsForValue().set(SESSION_PREFIX+session.getId(),session,DEFAULT_TIME_OUT, TimeUnit.MINUTES)方法用于将会话信息保存到Redis中,并设置会话的过期时间。为了保持这两个过期时间的同步更新,可以在SessionDAO的实现类中进行处理。

具体来说,可以在SessionDAO的实现类中定义一个常量,用于表示会话的默认过期时间。然后,在实现SessionDAO接口的create(Session session)方法和update(Session session)方法中,分别使用SecurityUtils.getSubject().getSession().getTimeout()方法获取当前用户的会话过期时间,和定义的常量进行比较,取较小值作为会话的过期时间。具体的实现方式如下:

public class RedisSessionDAO implements SessionDAO {
    private RedisTemplate<String, Object> redisTemplate;
    private static final long DEFAULT_EXPIRE_TIME = 30; // 默认过期时间,单位为分钟

    @Override
    public Serializable create(Session session) {
        // 获取当前用户的会话过期时间
        long expireTime = session.getTimeout() / 1000; // 转换为秒
        if (expireTime > DEFAULT_EXPIRE_TIME * 60) {
            expireTime = DEFAULT_EXPIRE_TIME * 60;
        }
        // 将会话信息保存到Redis中,并设置过期时间
        redisTemplate.opsForValue().set(SESSION_PREFIX + session.getId(), session, expireTime, TimeUnit.SECONDS);
        return session.getId();
    }

    @Override
    public void update(Session session) throws UnknownSessionException {
        // 获取当前用户的会话过期时间
        long expireTime = session.getTimeout() / 1000; // 转换为秒
        if (expireTime > DEFAULT_EXPIRE_TIME * 60) {
            expireTime = DEFAULT_EXPIRE_TIME * 60;
        }
        // 将会话信息保存到Redis中,并设置过期时间
        redisTemplate.opsForValue().set(SESSION_PREFIX + session.getId(), session, expireTime, TimeUnit.SECONDS);
    }
}

在上述代码中,DEFAULT_EXPIRE_TIME表示会话的默认过期时间,单位为分钟。在create(Session session)方法和update(Session session)方法中,首先使用session.getTimeout()方法获取当前用户的会话过期时间,然后将其转换为秒,并与DEFAULT_EXPIRE_TIME * 60进行比较,取较小值作为会话的过期时间。最后,将会话信息保存到Redis中,并设置过期时间为计算出的会话过期时间。这样,就可以保持会话过期时间的同步更新了。


在以上案例的基础上,我通过运用以上的知识点,解决我在项目中设置的客户自行选择系统超时登录时间,最开始,我卡在Shiro中调用Redis中的saveSession,此处代码如下:

public void saveSession(Session session){
        if(session != null && session.getId() != null){
            //设置Session的过期时间,以分钟计算时间。之前没设置,系统默认30分钟过期,也就是1800000ms
            //session.setTimeout(DEFAULT_TIME_OUT*1000*60); //这里自定义时间*60*1000ms,自定义时间按照分钟计时。
            long expireTime = session.getTimeout() / 60000; // 转换为分
            //会话过期时间
            redisTemplate.opsForValue().set("session前缀(自定义)"+session.getId(),session,expireTime, TimeUnit.MINUTES);
        }
    }

在如上代码中,我们可以设置在Redis的过期时间,但是你看到,我们设置的时间来自Session,那么我重点考虑的就是Session的timeout时间来自何处。考虑到我们使用Shiro中的登录,那么我们主要考虑在Shiro的授权和认证方面。
我主要是在认证方面出来doGetAuthenticationInfo也就是这个时间我需要在用户登录后再修改值,并在用户重新登录后生效。

具体处理思路,我个人的思路,我们先在用户登录后拿到用户的登录信息后,根据用户所在的公司查询到当前公司管理员所设置的系统超时时间,然后将他设置为我们的Session缓存时间:

部分代码如下:

//登录之后
            if(iErpConfigService.findByCompany(user.getCompany()) != null){
                System.out.println("miaow==>"+iErpConfigService.findByCompany(user.getCompany()).getExpirationTime() *1000*60);              
//由于系统的默认时间为毫秒,故而我们将分钟转换为毫秒
                SecurityUtils.getSubject().getSession().setTimeout(iErpConfigService.findByCompany(user.getCompany()).getExpirationTime() *1000*60);
                System.out.println("miaow + Session Time"+ subject.getSession().getTimeout());
            }

已经在这里设置了Session的缓存时间,之后Shiro会调用saveSession中的代码,也就是在那个时候我们将时间同步到redis中去,也就是给redis设置过期时间,切记,redis中是以计时。


标签:Session,过期,Redis,会话,session,时间,超时,Shiro
From: https://blog.51cto.com/miaow/8947872

相关文章

  • 【Java 进阶篇】Jedis 操作 Hash:Redis中的散列类型
    在Redis中,Hash是一种存储键值对的数据结构,它适用于存储对象的多个属性。Jedis作为Java开发者与Redis交互的工具,提供了丰富的API来操作Hash类型。本文将深入介绍Jedis如何操作Redis中的Hash类型数据,通过生动的代码示例和详细的解释,助你轻松掌握Jedis中Hash的各种操作。Jedis中Hash的......
  • redis配置
    1、redis-server配置文件名&------------------以哪个配置文件启动,不知道配置文件名以默认配置启动(默认配置≠redis.conf),可以复制redis.conf启动过个redis服务。  配置:1、daemonizeno|yes------------配置redis服务为守护模式2、pidfile/var/run/redis_6379.pid---......
  • Redis 哨兵集群搭建并使用 RedisTemplate 实现读写分离
    上篇博客介绍的Redis主从集群搭建,有一个缺点就是master和slave的角色是固定的,不会发生变化。一旦master节点宕机,那么集群就只能提供读服务,无法提供写服务。本篇博客介绍Redis哨兵集群的搭建,可以监控Redis集群的master和slave节点,最重要的是一旦master宕机,哨兵集......
  • Redis7 数据双写一致性
    1、缓存双写一致性如果redis中有数据,需要和数据库中的值相同如果redis中无数据,数据库中的值要是最新值,且准备回写redis缓存细分1、只读缓存2、读写缓存2.1、同步直写策略写数据库后也同步写redis缓存,缓存和数据库中的数据一致对于读写缓存来说,要想保证缓存和数据库中的数据......
  • Redis_实战
    Redis_实战部署:前端:部署在Nginx后端:部署在tomcat短信登录session原理:每一个session都有一个id,当你访问tomcat服务器时,id就自动写到coockie中了,以后请求就带着id,就可以根据id找到session。(每一个浏览器再发请求时都有一个独立的session)session在服务器端,coockie在客户端。......
  • RedissonLock 使用场景以及优缺点分析
    RedissonLock是Redisson库提供的一种基于Redis实现的分布式锁。以下是如何使用RedissonLock以及其优缺点:使用RedissonLock:初始化Redisson客户端:Configconfig=newConfig();config.useSingleServer().setAddress("redis://localhost:6379");RedissonClientredisson......
  • redis_原理
    redis_原理数据结构1.动态字符串SDSC语言字符串存在的问题:获取字符串长度需要通过运算非二进制安全不可修改redis构建了一种新的字符串结构,简单动态字符串SimpleDynamicStringSDSRedis是C语言实现的,其中SDS是一个结构体,属性包括:uint8_tlen:buf已保存的字符串字节数......
  • Redis_高级
    Redis_高级分布式缓存单点Redis的问题:数据丢失问题:实现Redis数据持久化并发能力问题:搭建主从集群,实现读写分离故障恢复问题:利用Redis哨兵,实现健康检测和自动恢复存储能力问题:搭建分片集群,利用插槽机制实现动态扩容数据丢失问题-数据持久化RDB基本流程fork主进程获......
  • redis配置允许远程连接
    1、修改redis.conf#允许访问的地址,127.0.0.1为本机,也就是只允许本机访问,修改为0.0.0.0,则可以在任意IP访问bind0.0.0.0#守护进程,修改为yes后即可后台运行daemonizeyes#密码,设置后访问Redis必须输入密码requirepass111222#关闭防护,允许远程连接protected-modeno#监听......
  • delphi模拟redis单元
    1unitg_uSdRedis;23interface45uses6Windows,7Messages,8SysUtils,9Variants,10Classes,11Graphics,12Controls,13Forms,14Dialogs,15IniFiles,16StdCtrls,17DateUtils;1819const......