package platform.config.shiro; import at.pollux.thymeleaf.shiro.dialect.ShiroDialect; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.cache.CacheManager; import org.apache.shiro.cache.ehcache.EhCacheManager; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler; import org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO; import org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator; 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.filter.authc.LogoutFilter; import org.apache.shiro.web.mgt.DefaultWebSecurityManager; import org.apache.shiro.web.servlet.SimpleCookie; import org.apache.shiro.web.session.mgt.DefaultWebSessionManager; import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.beans.factory.config.MethodInvokingFactoryBean; import org.springframework.cache.ehcache.EhCacheManagerFactoryBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import platform.modules.sys.log.service.LogService; import platform.modules.sys.shiro.AuthenticationRealm; import platform.modules.sys.shiro.CredentialsMatcher; import platform.modules.sys.shiro.DefaultFormAuthenticationFilter; import platform.modules.sys.shiro.filter.LoginFilter; import platform.modules.sys.shiro.filter.SystemLogoutFilter; import platform.modules.sys.shiro.filter.TokenFilter; import javax.servlet.Filter; import java.util.LinkedHashMap; import java.util.Map; /** * Shiro配置 * * @author lhf */ @Configuration public class ShiroConfig { /** * ShiroFilterFactoryBean 处理拦截资源文件问题。 * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,以为在 * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager *

* Filter Chain定义说明 * 1、一个URL可以配置多个Filter,使用逗号分隔 * 2、当设置多个过滤器时,全部验证通过,才视为通过 * 3、部分过滤器可指定参数,如perms,roles */ @Bean(name = "shiroFilter") public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager, LogService logService) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 必须设置 SecurityManager shiroFilterFactoryBean.setSecurityManager(securityManager); // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面 // shiroFilterFactoryBean.setLoginUrl("/home"); shiroFilterFactoryBean.setLoginUrl("/index"); // 登录成功后要跳转的链接 // shiroFilterFactoryBean.setSuccessUrl("/admin/home"); //未授权界面,注:注解方式验证权限不好使; // shiroFilterFactoryBean.setUnauthorizedUrl("/admin/403"); //自定义登出过滤器,设置登出后跳转地址 Map filters = new LinkedHashMap(); //自定义登录过滤器 filters.put("myLogin", loginFilter()); //自定义限制同一账号登录数量filter //自定义退出跳转页面 LogoutFilter logoutFilter = new SystemLogoutFilter(logService); //logoutFilter.setRedirectUrl("/admin/login"); //logoutFilter.setRedirectUrl("/home/login"); logoutFilter.setRedirectUrl("/index"); filters.put("myLogout", logoutFilter); filters.put("authc", new DefaultFormAuthenticationFilter(logService)); //手机端退出登录跳转页面 LogoutFilter mobileLogoutFilter = new SystemLogoutFilter(logService); mobileLogoutFilter.setRedirectUrl("/mobile/login"); filters.put("mobileLogout", mobileLogoutFilter); //新门户退出 LogoutFilter platformLogout = new SystemLogoutFilter(logService); mobileLogoutFilter.setRedirectUrl("/index"); filters.put("platformLogout", platformLogout); //门户工业载体过滤器 filters.put("industry", new TokenFilter()); shiroFilterFactoryBean.setFilters(filters); //过虑器链定义,从上向下顺序执行,一般将/**放在最下边 Map filterChainDefinitionMap = new LinkedHashMap(); //配置退出过滤器,其中的具体的退出代码Shiro已经替我们实现了 filterChainDefinitionMap.put("/admin/logout", "myLogout"); //配置退出过滤器-手机端 filterChainDefinitionMap.put("/mobile/logout", "mobileLogout"); //配置退出过滤器-新门户 filterChainDefinitionMap.put("/platform/logout", "platformLogout"); //登录请求匿名访问 filterChainDefinitionMap.put("/admin/login", "myLogin"); filterChainDefinitionMap.put("/mobile/login", "myLogin"); filterChainDefinitionMap.put("/home/login", "myLogin"); //过滤链定义,从上向下顺序执行,一般将放在最为下边:这是一个坑呢,一不小心代码就不好使了; //authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问 filterChainDefinitionMap.put("/government/activity/getAllEvents", "anon"); filterChainDefinitionMap.put("/government/activity/getEventList", "anon"); filterChainDefinitionMap.put("/project/**", "authc"); filterChainDefinitionMap.put("/projectDeclaration/**", "authc"); filterChainDefinitionMap.put("/admin/**", "authc"); filterChainDefinitionMap.put("/government/**", "authc"); filterChainDefinitionMap.put("/build/**", "authc"); filterChainDefinitionMap.put("/mobile/**", "authc"); filterChainDefinitionMap.put("/super/**", "authc"); filterChainDefinitionMap.put("/street/**", "authc"); filterChainDefinitionMap.put("/common/index", "authc"); filterChainDefinitionMap.put("/export/*", "authc"); filterChainDefinitionMap.put("/area/*", "authc"); filterChainDefinitionMap.put("/stockLand/**", "authc"); filterChainDefinitionMap.put("/projectApplication/**", "authc"); filterChainDefinitionMap.put("/projectApprove/**", "authc"); filterChainDefinitionMap.put("/upload/*", "anon"); filterChainDefinitionMap.put("/message/getMyRemind", "authc"); filterChainDefinitionMap.put("/platform/streets", "anon"); filterChainDefinitionMap.put("/carrier/checkCarrier", "anon"); filterChainDefinitionMap.put("/community/streets", "anon"); //工业载体 filterChainDefinitionMap.put("/community/*", "industry"); filterChainDefinitionMap.put("/carrier/*", "industry"); filterChainDefinitionMap.put("/map/api/investments/*", "industry"); filterChainDefinitionMap.put("/contract/*", "industry"); filterChainDefinitionMap.put("/investment/*", "industry"); filterChainDefinitionMap.put("/investment", "industry"); filterChainDefinitionMap.put("/front/investment/*", "industry"); filterChainDefinitionMap.put("/intention/*", "industry"); filterChainDefinitionMap.put("/rental", "industry"); filterChainDefinitionMap.put("/rental/**", "industry"); // filterChainDefinitionMap.put("/rentals", "industry"); //filterChainDefinitionMap.put("/*", "authc"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } /** * securityManager安全管理器 * Shiro的核心安全接口,这个属性是必须的 * * @return */ @Bean(name = "securityManager") public SecurityManager getSecurityManager(EhCacheManagerFactoryBean ehCacheManagerFactoryBean) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); //注入自定义Realm securityManager.setRealm(getAuthenticationRealm()); //注入缓存管理器 securityManager.setCacheManager(getCacheShiroManage(ehCacheManagerFactoryBean)); //注入session管理器 securityManager.setSessionManager(getSessionManage()); return securityManager; } /** * 自定义身份认证realm; * * @return */ @Bean public AuthenticationRealm getAuthenticationRealm() { AuthenticationRealm authenticationRealm = new AuthenticationRealm(); //将凭证匹配器设置到realm中,realm按照凭证匹配器的要求进行散列 authenticationRealm.setCredentialsMatcher(getHashedCredentialsMatcher()); //配置缓存 //开启缓存 authenticationRealm.setCachingEnabled(true); //开启认证缓存 authenticationRealm.setAuthenticationCachingEnabled(false); //设置认证缓存的名称对应ehcache中配置 // authenticationRealm.setAuthenticationCacheName("goodAuthenticationCache"); //开启授权信息缓存 authenticationRealm.setAuthorizationCachingEnabled(true); //设置授权缓存的名称对应ehcache中配置 authenticationRealm.setAuthorizationCacheName("goodAuthorizationCache"); return authenticationRealm; } /** * 凭证匹配器 指定密码匹配规则 * * @return */ @Bean(name = "hashedCredentialsMatcher") public HashedCredentialsMatcher getHashedCredentialsMatcher() { CredentialsMatcher credentialsMatcher = new CredentialsMatcher(); credentialsMatcher.setHashAlgorithmName("MD5");//散列算法:这里使用MD5算法; credentialsMatcher.setHashIterations(1); //散列的次数,比如散列两次,相当于 md5(md5("")); credentialsMatcher.setStoredCredentialsHexEncoded(true); return credentialsMatcher; } /** * Shiro生命周期处理器 * 保证实现了Shiro内部lifecycle函数的bean执行 * * @return */ @Bean(name = "lifecycleBeanPostProcessor") public LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } /** * 会话管理器 * * @return */ @Bean(name = "sessionManager") public DefaultWebSessionManager getSessionManage() { DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); //session的失效时长,单位毫秒 sessionManager.setGlobalSessionTimeout(3600000); //60分钟失效 sessionManager.setSessionValidationScheduler(getExecutorServiceSessionValidationScheduler()); sessionManager.setSessionValidationSchedulerEnabled(true); //删除失效的session sessionManager.setDeleteInvalidSessions(true); sessionManager.setSessionIdCookieEnabled(true); sessionManager.setSessionIdCookie(getSessionIdCookie()); sessionManager.setSessionDAO(getSessionDao()); //去除浏览器地址栏中url中JSESSIONID参数 sessionManager.setSessionIdUrlRewritingEnabled(false); // -----可以添加session 创建、删除的监听器 return sessionManager; } /** * 会话DAO * * @return */ @Bean(name = "sessionDao") public EnterpriseCacheSessionDAO getSessionDao() { EnterpriseCacheSessionDAO sessionDAO = new EnterpriseCacheSessionDAO(); sessionDAO.setActiveSessionsCacheName("shiro-activeSessionCache"); sessionDAO.setSessionIdGenerator(getSessionIdGenerator()); return sessionDAO; } /** * 会话ID生成器 * * @return */ @Bean(name = "sessionIdGenerator") public JavaUuidSessionIdGenerator getSessionIdGenerator() { JavaUuidSessionIdGenerator sessionIdGenerator = new JavaUuidSessionIdGenerator(); return sessionIdGenerator; } /** * 缓存管理器 使用Ehcache实现 * * @return */ @Bean(name = "cacheShiroManager") public CacheManager getCacheShiroManage(EhCacheManagerFactoryBean ehCacheManagerFactoryBean) { EhCacheManager ehCacheManager = new EhCacheManager(); // ehCacheManager.setCacheManagerConfigFile("classpath:ehcache-shiro.xml"); ehCacheManager.setCacheManager(ehCacheManagerFactoryBean.getObject()); return ehCacheManager; } /** * 会话Cookie模板 * * @return */ @Bean(name = "sessionIdCookie") public SimpleCookie getSessionIdCookie() { SimpleCookie cookie = new SimpleCookie("sid"); cookie.setHttpOnly(true); cookie.setMaxAge(-1); return cookie; } /** * 会话验证调度器 * * @return */ @Bean(name = "sessionValidationScheduler") public ExecutorServiceSessionValidationScheduler getExecutorServiceSessionValidationScheduler() { ExecutorServiceSessionValidationScheduler scheduler = new ExecutorServiceSessionValidationScheduler(); scheduler.setInterval(3600000);//每隔60分钟验证清理失效的session return scheduler; } /** * 相当于调用SecurityUtils.setSecurityManager(securityManager) * * @return */ @Bean public MethodInvokingFactoryBean getMethodInvokingFactoryBean(EhCacheManagerFactoryBean ehCacheManagerFactoryBean) { MethodInvokingFactoryBean factoryBean = new MethodInvokingFactoryBean(); factoryBean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager"); factoryBean.setArguments(new Object[]{getSecurityManager(ehCacheManagerFactoryBean)}); return factoryBean; } /** * 开启Shiro的注解(如@RequiresRoles,@RequiresPermissions),需借助SpringAOP扫描使用Shiro注解的类,并在必要时进行安全逻辑验证 * 配置以下两个bean即可实现此功能 * * @return */ @Bean @DependsOn("lifecycleBeanPostProcessor") public DefaultAdvisorAutoProxyCreator getAutoProxyCreator() { DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator(); creator.setProxyTargetClass(true); return creator; } @Bean public AuthorizationAttributeSourceAdvisor getAuthorizationAttributeSourceAdvisor(EhCacheManagerFactoryBean ehCacheManagerFactoryBean) { AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor(); advisor.setSecurityManager(getSecurityManager(ehCacheManagerFactoryBean)); return advisor; } /* * @methodName: loginFilter * @param: [] * @description:登录过滤器 * @return: com.jk.shiro.LoginFilter * @author: cuiP * @date: 2017/7/28 16:27 * @version: V1.0.0 */ @Bean public LoginFilter loginFilter() { return new LoginFilter(); } /** * ShiroDialect,为了在thymeleaf里使用shiro的标签的bean * * @return */ @Bean public ShiroDialect shiroDialect() { return new ShiroDialect(); } }