Shiro--会话与角色权限信息缓存

  1. 会话
    Shiro可以扩展Session至第三方缓存中,可以实现分布式下的缓存共享,如redis的话实现RedisSessionDao接口即可,本质为将session序列化后存储到redis中。
@Component
public class RedisSessionDao extends AbstractSessionDAO {

    private static Logger logger = LoggerFactory.getLogger(AbstractSessionDAO.class);

    @Autowired
    private JedisPool jedisPool;

    private static final String SHIRO_SESSION_ID_PREFIX="SHIRO_SESSION_ID:";

    /**
     *
     * @param session
     */
    private void saveDession(Session session){
        if(session==null){
            return;
        }
        Jedis jedis=null;
        try{
            jedis = jedisPool.getResource();
            byte[] key=(SHIRO_SESSION_ID_PREFIX+session.getId().toString()).getBytes();
            jedis.set(key, SerializationUtils.serialize(session));
            jedis.expire(key,600);
        }finally {
            if(jedis!=null){
                jedis.close();
            }
        }
    }

    @Override
    protected Serializable doCreate(Session session) {
        logger.info("----------------RedisSessionDao->doCreate---------------------------");
        Serializable sessionId = generateSessionId(session);
        logger.info("创建session:sessionId;{}",sessionId);
        assignSessionId(session,sessionId);
        saveDession(session);
        return  sessionId;
    }

    @Override
    protected Session doReadSession(Serializable sessionId) {
        logger.info("----------------RedisSessionDao->doReadSession--------------------------");
        if(sessionId==null){
            return null;
        }
        logger.info("读取session信息,sessionId为{}",sessionId);
        byte[] key = (SHIRO_SESSION_ID_PREFIX + sessionId.toString()).getBytes();
        Jedis jedis=null;
        try{
             jedis= jedisPool.getResource();
            byte[] value=jedis.get(key);
            return (Session) SerializationUtils.deserialize(value);
        }finally {
            if(jedis!=null){
                jedis.close();
            }
        }
    }

    @Override
    public void update(Session session) throws UnknownSessionException {
        logger.info("----------------RedisSessionDao->update--------------------------");
        logger.info("更新session信息,");
        saveDession(session);

    }

    @Override
    public void delete(Session session) {
        logger.info("----------------RedisSessionDao->delete--------------------------");
        if(session==null||session.getId()==null){
            return;
        }
        logger.info("删除session信息,sessionId为:{}",session.getId().toString());
        byte[] key=(SHIRO_SESSION_ID_PREFIX+session.getId().toString()).getBytes();
        Jedis jedis=null;
        try{
            jedis= jedisPool.getResource();
            jedis.del(key);
        }finally {
            if(jedis!=null){
                jedis.close();
            }
        }
    }

    @Override
    public Collection<Session> getActiveSessions() {
        Jedis jedis=null;
        try{
            jedis= jedisPool.getResource();
            Set<byte[]> keys = jedis.keys((SHIRO_SESSION_ID_PREFIX + "*").getBytes());
            Set<Session> sessions=new HashSet<>();
            if(CollectionUtils.isEmpty(keys)){
                return sessions;
            }
            for (byte[] key:keys){
                Session session=(Session)SerializationUtils.deserialize(jedis.get(key));
                sessions.add(session);
            }
            return sessions;
        }finally {
            if(jedis!=null){
                jedis.close();
            }
        }
    }
}

shiro的配置文件中SecurityManager注入sessionManager

<!--创建SecurityManager-->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="customerRealm"/>
		<property name="sessionManager" ref="sessionManager"/>
	</bean>
	<!--会话管理-->
	<bean id="sessionManager" class="com.test.shiro.realm.CustomSessionManager">
		<property name="sessionDAO" ref="redisSessionDao"/>
	</bean>
	<bean id="redisSessionDao" class="com.test.shiro.redis.RedisSessionDao"/>

踩到一个坑,在idea中开发,Tomcat启动后,我在idea中不设置tomcat启动成功自动在浏览器中访问项目,控制台不停的执行doReadSession和update方法,网上各种说法都有,有说时shiro设计的问题,还有说是shiro集成quartz。在定时清除过期的session,未果,开始chrome启动说”windows找不到文件 chrome 请确定文件名是否正确“,没在意,解决后不停的调用doReadSession和update方法的问题也不出现了,有点迷,问题原因未知。。。在这里插入图片描述
就没报名

  1. 角色信息缓存化
    shiro支持角色信息与权限信息添加到缓存中,如果缓存不存在,执行AuthorizingRealm的doGetAuthorizationInfo方法,从数据库中获取角色与权限信息,实现CacheManager接口
public class RedisCacheManager implements CacheManager {

    @Autowired
    private RedisCache redisCache;

    @Override
    public <K, V> Cache<K, V> getCache(String s) throws CacheException {
        return redisCache;
    }
}

注入的RedisCache,实现Cache<K,V>接口

@Component
public class RedisCache<K,V> implements Cache<K,V> {

    private static Logger logger = LoggerFactory.getLogger(RedisCache.class);

    private static final String CACHE_PREFIX="shiro-cache:";

    private static final int CACHE_EXPIRE_TIME=10*60;

    @Autowired
    private JedisPool jedisPool;

    private byte[] getKey(K k){
        if(k instanceof String){
            return (CACHE_PREFIX+k).getBytes();
        }
        return SerializationUtils.serialize(k);
    }

    @Override
    public V get(K k) throws CacheException {
        logger.info("从redis中获取权限数据,k为{}",k);
        Jedis jedis=null;
        try {
            jedis=jedisPool.getResource();
            byte[] value = jedis.get(getKey(k));
            if(value!=null){

                return (V)SerializationUtils.deserialize(value);
            }
            return null;
        }finally {
            if(jedis!=null){
                jedis.close();
            }
        }
    }

    @Override
    public V put(K k, V v) throws CacheException {
        logger.info("将角色与权限信息添加到缓存中k为{}",k);
        Jedis jedis=null;
        try {
            byte[] key=getKey(k);
            byte[] value=SerializationUtils.serialize(v);

            jedis=jedisPool.getResource();
            jedis.set(key,value);
            jedis.expire(key,CACHE_EXPIRE_TIME);
        }finally {
            if(jedis!=null){
                jedis.close();
            }
        }
        return v;
    }

    @Override
    public V remove(K k) throws CacheException {
        Jedis jedis=null;
        try {
            byte[] key=getKey(k);
            jedis=jedisPool.getResource();
            byte[] value = jedis.get(key);
            jedis.del(key);

            if(value!=null){
                return (V) SerializationUtils.deserialize(value);
            }
        }finally {
            if(jedis!=null){
                jedis.close();
            }
        }
        return null;
    }

    @Override
    public void clear() throws CacheException {
        //不需要重写,
    }

    @Override
    public int size() {
        return 0;
    }

    @Override
    public Set<K> keys() {
        return null;
    }

    @Override
    public Collection<V> values() {
        return null;
    }
}

同样Shiro配置DefaultWebSecurityManager注入cacheManager

<!--创建SecurityManager-->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="customerRealm"/>
		<property name="sessionManager" ref="sessionManager"/>
		<property name="cacheManager" ref="cacheManager"/>
		<property name="rememberMeManager" ref="cookieRememberMeManager"/>
	</bean>
	<bean id="customerRealm" class="com.test.shiro.realm.CustomerRealm">
		<property name="credentialsMatcher" ref="credentialsMatcher"/>
	</bean>
	<bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
		<property name="hashAlgorithmName" value="md5"/>
		<!--一次加密-->
		<property name="hashIterations" value="1"/>
	</bean>

	<!--会话管理-->
	<bean id="sessionManager" class="com.test.shiro.realm.CustomSessionManager">
		<property name="sessionDAO" ref="redisSessionDao"/>
	</bean>
	<bean id="redisSessionDao" class="com.test.shiro.redis.RedisSessionDao"/>

	<!--角色权限缓存管理-->
	<bean id="cacheManager" class="com.test.shiro.cache.RedisCacheManager"/>

Cookie过期时间设置

<!--记住我功能-->
	<bean id="cookieRememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
		<property name="cookie" ref="simpleCookie"/>
	</bean>
	<bean id="simpleCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
		<constructor-arg value="rememberMe"/>
		<!--Cookie的过期时间-->
		<property name="maxAge" value="600"/>
	</bean>

同样Shiro的配置文件中DefaultWebSecurityManager注入rememberMeManager

<!--创建SecurityManager-->
	<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
		<property name="realm" ref="customerRealm"/>
		<property name="sessionManager" ref="sessionManager"/>
		<property name="cacheManager" ref="cacheManager"/>
		<property name="rememberMeManager" ref="cookieRememberMeManager"/>
	</bean>

登陆的位置UsernamePasswordToken设置Remember为true

public Object testLogin(User user, HttpServletRequest request, HttpServletResponse response){
        logger.info("-----------登陆校验------------------");
        Subject subject= SecurityUtils.getSubject();
        UsernamePasswordToken token=new UsernamePasswordToken(user.getUsername(),user.getPassword());

        //密码校验
        try{
            token.setRememberMe(true);
            subject.login(token);
            logger.info("是否已认证:"+subject.isAuthenticated());
        }catch (Exception e){
            logger.error("校验异常{}",e);
            return "登陆失败";
        }
        return "登陆成功";
    }
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值