ShiroConfig.java 9.02 KB
Newer Older
liqin's avatar
liqin committed
1
package cn.chnmuseum.party.conf;
liqin's avatar
liqin committed
2

liqin's avatar
liqin committed
3 4 5 6
import cn.chnmuseum.party.auth.filter.JwtFilter;
import cn.chnmuseum.party.auth.realm.MyShiroRealm;
import cn.chnmuseum.party.model.PermissionInit;
import cn.chnmuseum.party.service.PermissionInitService;
liqin's avatar
liqin committed
7 8 9 10 11 12 13 14
import org.apache.shiro.mgt.DefaultSessionStorageEvaluator;
import org.apache.shiro.mgt.DefaultSubjectDAO;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.crazycake.shiro.RedisCacheManager;
liqin's avatar
liqin committed
15
import org.crazycake.shiro.RedisManager;
liqin's avatar
liqin committed
16 17 18
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
liqin's avatar
liqin committed
19
import org.springframework.beans.factory.annotation.Value;
liqin's avatar
liqin committed
20
import org.springframework.context.annotation.Bean;
wzp's avatar
wzp committed
21
import org.springframework.context.annotation.Configuration;
liqin's avatar
liqin committed
22
import org.springframework.context.annotation.DependsOn;
wzp's avatar
wzp committed
23
import org.springframework.core.annotation.Order;
liqin's avatar
liqin committed
24
import redis.clients.jedis.JedisPoolConfig;
liqin's avatar
liqin committed
25 26 27 28 29 30 31

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

wzp's avatar
wzp committed
32 33
@Configuration
@Order(-2)
liqin's avatar
liqin committed
34 35 36
public class ShiroConfig {

    private static final Logger logger = LoggerFactory.getLogger(ShiroConfig.class);
liqin's avatar
liqin committed
37
    private static final String CACHE_KEY = "shiro:cache:";
liqin's avatar
liqin committed
38 39

    @Resource
liqin's avatar
liqin committed
40
    private PermissionInitService permissionInitService;
liqin's avatar
liqin committed
41

liqin's avatar
liqin committed
42 43 44 45 46 47 48 49
    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;
    @Value("${spring.redis.timeout}")
    private int timeout;
    @Value("${spring.redis.password}")
    private String password;
liqin's avatar
liqin committed
50 51 52 53 54 55
    @Value("${spring.redis.jedis.pool.min-idle}")
    private int minIdle;
    @Value("${spring.redis.jedis.pool.max-idle}")
    private int maxIdle;
    @Value("${spring.redis.jedis.pool.max-active}")
    private int maxActive;
liqin's avatar
liqin committed
56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88

    /**
     * ShiroFilterFactoryBean 处理拦截资源文件问题。
     * <p>
     * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在
     * <p>
     * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager
     * <p>
     * <p>
     * <p>
     * Filter Chain定义说明 1、一个URL可以配置多个Filter,使用逗号分隔 2、当设置多个过滤器时,全部验证通过,才视为通过
     * <p>
     * 3、部分过滤器可指定参数,如perms,roles
     */
    @Bean("shiroFilter")
    public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 必须设置 SecurityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        // 未授权界面
        shiroFilterFactoryBean.setUnauthorizedUrl("/403");

        // 自定义拦截器
        Map<String, Filter> filtersMap = shiroFilterFactoryBean.getFilters();
        filtersMap.put("jwt", new JwtFilter());
        shiroFilterFactoryBean.setFilters(filtersMap);

        // 权限控制map
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
        List<PermissionInit> list = this.permissionInitService.selectAll();
        for (PermissionInit permissionInit : list) {
            filterChainDefinitionMap.put(permissionInit.getUrl(), permissionInit.getPermissionInit());
        }
wzp's avatar
wzp committed
89
        //访问401和404页面不通过我们的Filter
liqin's avatar
liqin committed
90 91 92 93
        filterChainDefinitionMap.put("/logout", "anon");
        filterChainDefinitionMap.put("/verifyCode", "anon");
        filterChainDefinitionMap.put("/ajaxLogin1", "anon");
        filterChainDefinitionMap.put("/verifyCode1", "anon");
liqin's avatar
liqin committed
94
        filterChainDefinitionMap.put("/loginByQrCode", "anon");
liqin's avatar
liqin committed
95
        filterChainDefinitionMap.put("/doc.html", "anon");
wzp's avatar
wzp committed
96
        filterChainDefinitionMap.put("/swagger-ui.html", "anon");
liqin's avatar
liqin committed
97
        filterChainDefinitionMap.put("/cmRestApi/equitment/key", "anon");
liqin's avatar
liqin committed
98 99 100 101 102 103 104
        filterChainDefinitionMap.put("/404", "anon");
        filterChainDefinitionMap.put("/500", "anon");

        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

liqin's avatar
liqin committed
105
    @Bean("securityManager")
liqin's avatar
liqin committed
106
    public DefaultWebSecurityManager securityManager() {
liqin's avatar
liqin committed
107 108 109 110 111
        logger.info("ShiroConfiguration.securityManager()");
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 设置realm
        securityManager.setRealm(myShiroRealm());
        // 自定义缓存实现 使用redis
liqin's avatar
liqin committed
112
        securityManager.setCacheManager(redisCacheManager());
liqin's avatar
liqin committed
113 114 115 116 117 118 119 120 121 122 123 124 125 126 127

        // 关闭shiro自带的session
        DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO();
        DefaultSessionStorageEvaluator defaultSessionStorageEvaluator = new DefaultSessionStorageEvaluator();
        defaultSessionStorageEvaluator.setSessionStorageEnabled(false);
        subjectDAO.setSessionStorageEvaluator(defaultSessionStorageEvaluator);
        securityManager.setSubjectDAO(subjectDAO);
        return securityManager;
    }

    /**
     * 身份认证realm; (这个需要自己写,账号密码校验;权限等)
     */
    @Bean
    public MyShiroRealm myShiroRealm() {
liqin's avatar
liqin committed
128 129 130 131 132 133 134 135 136 137 138 139 140
//        //开启全局缓存配置
//        myShiroRealm.setCachingEnabled(true);
//        //启用身份验证缓存,即缓存AuthenticationInfo信息,默认false
//        myShiroRealm.setAuthenticationCachingEnabled(true);
//        //启用授权缓存,即缓存AuthorizationInfo信息,默认false
//        myShiroRealm.setAuthorizationCachingEnabled(true);
//
//        //为了方便操作,我们给缓存起个名字
//        myShiroRealm.setAuthenticationCacheName("authcCache");
//        myShiroRealm.setAuthorizationCacheName("authzCache");
//
//        //注入缓存实现
//        myShiroRealm.setCacheManager(redisCacheManager());
liqin's avatar
liqin committed
141 142 143 144 145 146 147 148 149
        return new MyShiroRealm();
    }

    /**
     * LifecycleBeanPostProcessor,这是个DestructionAwareBeanPostProcessor的子类,
     * 负责org.apache.shiro.util.Initializable类型bean的生命周期的,初始化和销毁。
     * 主要是AuthorizingRealm类的子类,以及EhCacheManager类。 Shiro生命周期处理器
     */
    @Bean
liqin's avatar
liqin committed
150
    public static LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
liqin's avatar
liqin committed
151 152 153 154 155 156 157 158 159 160 161 162 163
        logger.info("ShiroConfiguration.getLifecycleBeanPostProcessor()");
        return new LifecycleBeanPostProcessor();
    }

    /**
     * DefaultAdvisorAutoProxyCreator,Spring的一个bean,由Advisor决定对哪些类的方法进行AOP代理。
     * 实现AOP式方法级权限检查
     */
    @Bean
    @DependsOn("lifecycleBeanPostProcessor")
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        logger.info("ShiroConfiguration.defaultAdvisorAutoProxyCreator()");
        DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
liqin's avatar
liqin committed
164
        //defaultAdvisorAutoProxyCreator.setUsePrefix(true);
liqin's avatar
liqin committed
165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180
        // 强制使用cglib,防止重复代理和可能引起代理出错的问题
        defaultAdvisorAutoProxyCreator.setProxyTargetClass(true);
        return defaultAdvisorAutoProxyCreator;
    }

    /**
     * 开启shiro的aop注解支持. 使用代理方式; 所以需要开启代码支持;
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        logger.info("ShiroConfiguration.authorizationAttributeSourceAdvisor()");
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }

liqin's avatar
liqin committed
181
    /**
liqin's avatar
liqin committed
182
     * 配置Redis管理器
liqin's avatar
liqin committed
183
     *
liqin's avatar
liqin committed
184
     * @return
liqin's avatar
liqin committed
185
     * @Attention 使用的是shiro-redis开源插件
liqin's avatar
liqin committed
186
     */
liqin's avatar
liqin committed
187
    @Bean
liqin's avatar
liqin committed
188 189
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
liqin's avatar
liqin committed
190
        redisManager.setHost(host + ":" + port);
liqin's avatar
liqin committed
191 192
        redisManager.setTimeout(timeout);
        redisManager.setPassword(password);
liqin's avatar
liqin committed
193 194 195 196 197
        JedisPoolConfig jedisPoolConfig = new JedisPoolConfig();
        jedisPoolConfig.setMaxTotal(maxIdle + maxActive);
        jedisPoolConfig.setMaxIdle(maxIdle);
        jedisPoolConfig.setMinIdle(minIdle);
        redisManager.setJedisPoolConfig(jedisPoolConfig);
liqin's avatar
liqin committed
198 199 200 201 202 203
        return redisManager;
    }

    /**
     * 用户授权信息Cache, 采用Redis
     */
liqin's avatar
liqin committed
204
    @Bean
liqin's avatar
liqin committed
205
    public RedisCacheManager redisCacheManager() {
liqin's avatar
liqin committed
206 207
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
liqin's avatar
liqin committed
208
        //redisCacheManager.setKeyPrefix(CACHE_KEY);
liqin's avatar
liqin committed
209 210 211
        // shiro-redis要求放在session里面的实体类必须有个id标识
        //这是组成redis中所存储数据的key的一部分
        redisCacheManager.setPrincipalIdFieldName("id");
liqin's avatar
liqin committed
212 213
        //用户权限信息缓存时间
        //redisCacheManager.setExpire(200000);
liqin's avatar
liqin committed
214 215 216
        return redisCacheManager;
    }

liqin's avatar
liqin committed
217
}