缓存管理就是把一些权限数据交给Redis,这里就不用重复的从数据库中拿到权限数据,进而提高效率。本文的只提供部分的代码,在Shiro会话管理基础上作扩充。

1.创建自定义缓存Manager

package com.benzhu.shiro.cache;

import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.apache.shiro.cache.CacheManager;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;

@Component("cacheManager")
public class RedisCacheManager implements CacheManager {

    @Resource
    private RedisCache redisCache;

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

2.创建缓存的增删查改

package com.benzhu.shiro.cache;

import com.benzhu.shiro.config.RedisConfig;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheException;
import org.springframework.stereotype.Component;
import org.springframework.util.SerializationUtils;

import javax.annotation.Resource;
import java.util.Collection;
import java.util.Set;

@Component
public class RedisCache<k,v> implements Cache<k,v> {

    @Resource
    private RedisConfig redisConfig;

    private final String CACHE_PREFIX = "imooc-cache:";

    private byte[] getkey(k k){
        if(k instanceof String){
            //判断K值是否为String类型 不是就直接返回序列化数组
            return (CACHE_PREFIX +k).getBytes();
        }
        return SerializationUtils.serialize(k);
    }

    @Override
    public v get(k key) throws CacheException {
        //查询
        System.out.println("从缓存中读取数据。");
        byte[] val = redisConfig.get(getkey(key));
        if(val != null){
            return (v) SerializationUtils.deserialize(val);
        }
        return null;
    }

    @Override
    public v put(k key, v value) throws CacheException {
        //增加
        byte[] k = getkey(key);
        byte[] val = SerializationUtils.serialize(value);
        redisConfig.set(k, val);
        redisConfig.expire(k, 600);
        return value;
    }

    @Override
    public v remove(k key) throws CacheException {
        //删除
        byte[] k = getkey(key);
        byte[] val = redisConfig.get(k);
        redisConfig.del(k);
        if(val != null){
            return (v) SerializationUtils.deserialize(val);
        }
        return null;
    }

    @Override
    public void clear() throws CacheException {
        //不要重写 等下把Redis的所有数据都清空了
    }

    @Override
    public int size() {
        //返回数量
        return 0;
    }

    @Override
    public Set<k> keys() {
        //查询全部key
        return null;
    }

    @Override
    public Collection<v> values() {
        //查询全部
        return null;
    }
}

3.配置自定义的CacheManager

package com.benzhu.shiro.Filter;

import com.benzhu.shiro.cache.RedisCacheManager;
import com.benzhu.shiro.realm.CustomRealm;
import com.benzhu.shiro.session.CustomSessionManager;
import com.benzhu.shiro.session.RedisSessionDao;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;
import javax.servlet.Filter;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfiguration {

    @Resource(name = "realm")
    private CustomRealm customRealm;
    @Resource(name = "redisSessionDao")
    private RedisSessionDao redisSessionDao;
    @Resource
    private RedisCacheManager redisCacheManager;

    @Bean(name="shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(@Qualifier("securityManager") DefaultWebSecurityManager manager) {
        ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
        bean.setSecurityManager(manager);
        //配置登录的url和登录成功的url以及验证失败的url
        bean.setLoginUrl("/login");
        bean.setUnauthorizedUrl("/error");

        //配置自定义的Filter
        Map<String, Filter> filtersMap = new LinkedHashMap<String, Filter>();
        filtersMap.put("roleOrFilter", new RolesOrFilter());
        bean.setFilters(filtersMap);
        //配置访问权限
        LinkedHashMap<String, String> filterChainDefinitionMap=new LinkedHashMap<>();
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/sublogin", "anon");
        filterChainDefinitionMap.put("/usererror", "anon");
        filterChainDefinitionMap.put("/roles1", "roles[admin]");
        filterChainDefinitionMap.put("/roles2", "roles[admin,user]");
        filterChainDefinitionMap.put("/permission1", "perms[user:update]");
        filterChainDefinitionMap.put("/permission2", "perms[user:update,user:select]");
        filterChainDefinitionMap.put("/roles3", "roleOrFilter[admin,user]");
        filterChainDefinitionMap.put("/**","authc");
        bean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return bean;
    }



    //配置核心安全事务管理器
    @Bean(name="securityManager")
    public DefaultWebSecurityManager securityManager(@Qualifier("sessionManager")CustomSessionManager sessionManager) {
        DefaultWebSecurityManager manager=new DefaultWebSecurityManager();
        //配置自定义Realm
        manager.setRealm(customRealm);
        //配置自定义sessionManager
        manager.setSessionManager(sessionManager);
        //配置自定义cacheManager,主要添加的就是底下这行
        manager.setCacheManager(redisCacheManager);
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher(); //创建加密对象
        matcher.setHashAlgorithmName("md5"); //加密的算法
        matcher.setHashIterations(1);//加密次数
        customRealm.setCredentialsMatcher(matcher); //放入自定义Realm
        return manager;
    }

    //以下是开启注解支持
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager){
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
        return authorizationAttributeSourceAdvisor;
    }

    //配置session
    @Bean(name="sessionManager")
    public CustomSessionManager sessionManager(){
        //把sessionManager注入Bean
        CustomSessionManager manager = new CustomSessionManager();
        manager.setSessionDAO(redisSessionDao);
        return manager;
    }
}

4.测试图

登陆后访问一个页面,从图中可以看出,在第二次访问刷新的时候就不会从数据库读取了。