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();
}
}