ShiroConfig.java 8.75 KB
Newer Older
licc's avatar
licc committed
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 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 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
package com.project.shiro.config;

import com.project.shiro.util.AuthenticationFilter;
import com.project.shiro.util.AuthenticationRealm;
import com.project.shiro.util.AuthorizationFilter;
import com.project.shiro.util.redis.ShiroRedisCacheManager;
import com.project.shiro.util.redis.ShiroRedisSessionDAO;
import org.apache.shiro.session.mgt.SessionManager;
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.apache.shiro.web.servlet.SimpleCookie;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;

import javax.servlet.Filter;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

/**
 * Description: shiro配置类
 * User: mxy
 * Date: 2019-04-16
 */
@Configuration
public class ShiroConfig {

    private static final transient Logger logger = LoggerFactory.getLogger(ShiroConfig.class);

    /**
     * 配置拦截器
     * <p>
     * 定义拦截URL权限,优先级从上到下
     * 1). anon  : 匿名访问,无需登录
     * 2). authc : 登录后才能访问
     * 3). logout: 登出
     * 4). frameperms : 自定义的过滤器
     * <p>
     * URL 匹配风格
     * 1). ?:匹配一个字符,如 /admin? 将匹配 /admin1,但不匹配 /admin 或 /admin/;
     * 2). *:匹配零个或多个字符串,如 /admin* 将匹配 /admin 或/admin123,但不匹配 /admin/1;
     * 3). **:匹配路径中的零个或多个路径,如 /admin/** 将匹配 /admin/a 或 /admin/a/b
     * <p>
     * 配置身份验证成功,失败的跳转路径
     */
    @Bean
    public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) {
        logger.info("进入Shiro拦截工厂");
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 设置securityManager
        shiroFilterFactoryBean.setSecurityManager(securityManager);

        // 自定义的过滤器
        Map<String, Filter> filterMap = new HashMap<>();
        // map里面key值要为过滤器的名称,value为过滤器对象
        filterMap.put("authc", authenticationFilter());
        filterMap.put("frameperms", authorizationFilter());
        // 将自定义的过滤器加入到过滤器集合中
        shiroFilterFactoryBean.setFilters(filterMap);

        // 设置拦截器集合
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        filterChainDefinitionMap.put("/admin/", "anon"); // 后台资源-匿名访问
        filterChainDefinitionMap.put("/admin/res/**", "anon"); // 静态资源-匿名访问
        filterChainDefinitionMap.put("/admin/anon/**", "anon"); // 后台可匿名访问资源-匿名访问
        filterChainDefinitionMap.put("/admin/login", "authc"); // 登录页面-身份认证
        filterChainDefinitionMap.put("/admin/logout", "logout");    // 用户退出,只需配置logout即可实现该功能
        filterChainDefinitionMap.put("/admin/common/**", "anon");  // 其他路径均需要身份认证,一般位于最下面,优先级最低
        filterChainDefinitionMap.put("/admin/**", "authc,frameperms");  // 其他路径均需要身份认证,一般位于最下面,优先级最低

        // 设置拦截器
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        shiroFilterFactoryBean.setLoginUrl("/admin/login");       // 登录的路径
//        shiroFilterFactoryBean.setUnauthorizedUrl("/admin/common/unauthorized.jhtml");  // 验证失败后跳转的路径
        logger.info("Shiro拦截工厂配置完成");
        return shiroFilterFactoryBean;
    }

    /**
     * 配置Shiro生命周期处理器
     */
    @Bean
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * 自动创建代理类,若不添加,Shiro的注解可能不会生效。
     */
    @Bean
    @DependsOn({"lifecycleBeanPostProcessor"})
    public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        advisorAutoProxyCreator.setProxyTargetClass(true);
        return advisorAutoProxyCreator;
    }

    /**
     * 开启Shiro的注解
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
        authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
        return authorizationAttributeSourceAdvisor;
    }

    /**
     * 配置加密匹配,使用MD5的方式,进行1024次加密
     */
//    @Bean
//    public HashedCredentialsMatcher hashedCredentialsMatcher() {
//        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
//        hashedCredentialsMatcher.setHashAlgorithmName("MD5");
//        hashedCredentialsMatcher.setHashIterations(1024);
//        return hashedCredentialsMatcher;
//    }

    /**
     * SecurityManager 安全管理器;Shiro的核心
     */
    @Bean
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 自定义的Realm
        securityManager.setRealm(authenticationShiroRealm());
        // 缓存管理
        securityManager.setCacheManager(shiroRedisCacheManager());
        // 会话管理
        securityManager.setSessionManager(sessionManager());
        return securityManager;
    }

    /**
     * 自定义Realm,可以多个
     */
    @Bean
    public AuthenticationRealm authenticationShiroRealm() {
        AuthenticationRealm authenticationRealm = new AuthenticationRealm();
        //authenticationRealm.setCredentialsMatcher(hashedCredentialsMatcher());
        return authenticationRealm;
    }

    /**
     * redis缓存管理
     */
    @Bean
    public ShiroRedisCacheManager shiroRedisCacheManager() {
        return new ShiroRedisCacheManager();
    }

    /**
     * 设置session会话管理者
     */
    @Bean
    public SessionManager sessionManager() {
        DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();
        defaultWebSessionManager.setSessionIdCookie(simpleCookie());
        defaultWebSessionManager.setSessionDAO(shiroRedisSessionDAO());
        return defaultWebSessionManager;
    }

    /**
     * session管理
     */
    @Bean
    public ShiroRedisSessionDAO shiroRedisSessionDAO() {
        return new ShiroRedisSessionDAO();
    }

cy's avatar
cy committed
178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198
    /**
     * 限制同一账号登录同时登录人数控制
     * @return
     */
    public KickoutSessionControlFilter kickoutSessionControlFilter(){
        KickoutSessionControlFilter kickoutSessionControlFilter = new KickoutSessionControlFilter();
        //使用cacheManager获取相应的cache来缓存用户登录的会话;用于保存用户—会话之间的关系的;
        //这里我们还是用之前shiro使用的redisManager()实现的cacheManager()缓存管理
        //也可以重新另写一个,重新配置缓存时间之类的自定义缓存属性
        kickoutSessionControlFilter.setCacheManager(cacheManager());
        //用于根据会话ID,获取会话进行踢出操作的;
        kickoutSessionControlFilter.setSessionManager(sessionManager());
        //是否踢出后来登录的,默认是false;即后者登录的用户踢出前者登录的用户;踢出顺序。
        kickoutSessionControlFilter.setKickoutAfter(false);
        //同一个用户最大的会话数,默认1;比如2的意思是同一个用户允许最多同时两个人登录;
        kickoutSessionControlFilter.setMaxSession(1);
        //被踢出后重定向到的地址;
        kickoutSessionControlFilter.setKickoutUrl("/kickout");
        return kickoutSessionControlFilter;
    }

licc's avatar
licc committed
199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
    /**
     * 这里需要设置一个cookie的名称  原因就是会跟原来的session的id值重复的
     */
    @Bean
    public SimpleCookie simpleCookie() {
        return new SimpleCookie("SHAREJSESSIONID");
    }


    @Bean
    public AuthenticationFilter authenticationFilter() {
        return new AuthenticationFilter();
    }

    @Bean
    public AuthorizationFilter authorizationFilter() {
        return new AuthorizationFilter();
    }

}