|
|
@@ -0,0 +1,300 @@
|
|
|
+package com.ytpm.config.shiro;
|
|
|
+
|
|
|
+import com.ytpm.util.MyRedisManager;
|
|
|
+import lombok.Data;
|
|
|
+import lombok.extern.slf4j.Slf4j;
|
|
|
+import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
|
|
|
+import org.apache.shiro.mgt.SecurityManager;
|
|
|
+import org.apache.shiro.session.mgt.SessionManager;
|
|
|
+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.crazycake.shiro.RedisCacheManager;
|
|
|
+import org.crazycake.shiro.RedisManager;
|
|
|
+import org.crazycake.shiro.RedisSessionDAO;
|
|
|
+import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
|
|
|
+import org.springframework.beans.factory.annotation.Autowired;
|
|
|
+import org.springframework.beans.factory.annotation.Value;
|
|
|
+import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
|
|
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
|
|
|
+import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication.Type;
|
|
|
+import org.springframework.boot.context.properties.ConfigurationProperties;
|
|
|
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
|
|
+import org.springframework.context.annotation.Bean;
|
|
|
+import org.springframework.context.annotation.Configuration;
|
|
|
+import org.springframework.web.filter.DelegatingFilterProxy;
|
|
|
+
|
|
|
+import javax.servlet.Filter;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.Map;
|
|
|
+
|
|
|
+/**
|
|
|
+ *
|
|
|
+ * @author gkHuang
|
|
|
+ *
|
|
|
+ */
|
|
|
+@Slf4j(topic = "shiro 自动装配")
|
|
|
+@Configuration
|
|
|
+@ConditionalOnWebApplication(type = Type.SERVLET)
|
|
|
+@ConditionalOnClass(value = { SecurityManager.class })
|
|
|
+@ConfigurationProperties(prefix = "shiro")
|
|
|
+@Data
|
|
|
+public class ShiroAutoConfiguration {
|
|
|
+
|
|
|
+ private static final String SHIRO_DIALECT = "shiroDialect";
|
|
|
+ private static final String SHIRO_FILTER = "shiroFilter";
|
|
|
+ private String hashAlgorithmName = "md5";// 加密方式
|
|
|
+ private int hashIterations = 2;// 散列次数
|
|
|
+ private String loginUrl = "/sys/toLogin";// 默认的登录页面
|
|
|
+ private String[] anonUrls;
|
|
|
+ private String logOutUrl;
|
|
|
+ private String[] authcUlrs;
|
|
|
+ @Value("${spring.redis.host}")
|
|
|
+ private static String redisHost;
|
|
|
+ @Value("${spring.redis.port}")
|
|
|
+ private static String redisPort;
|
|
|
+ @Value("${spring.redis.database}")
|
|
|
+ private static int redisDB;
|
|
|
+ @Value("${spring.redis.password}")
|
|
|
+ private static String redisPwd;
|
|
|
+
|
|
|
+ @Autowired
|
|
|
+ private MyRedisManager myRedisManager;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 配置shiro的过滤器
|
|
|
+ *
|
|
|
+ */
|
|
|
+ @Bean(SHIRO_FILTER)
|
|
|
+ public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager) {
|
|
|
+ ShiroFilterFactoryBean factoryBean = new ShiroFilterFactoryBean();
|
|
|
+ // 设置安全管理器
|
|
|
+ factoryBean.setSecurityManager(securityManager);
|
|
|
+ // 设置未登录的时要跳转的页面
|
|
|
+ factoryBean.setLoginUrl(loginUrl);
|
|
|
+ Map<String, String> filterChainDefinitionMap = new HashMap<>();
|
|
|
+ // 设置放行的路径
|
|
|
+ if (anonUrls != null && anonUrls.length > 0) {
|
|
|
+ for (String anon : anonUrls) {
|
|
|
+ filterChainDefinitionMap.put(anon, "anon");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ // 设置登出的路径
|
|
|
+ if (null != logOutUrl) {
|
|
|
+ filterChainDefinitionMap.put(logOutUrl, "logout");
|
|
|
+ }
|
|
|
+ // 设置拦截的路径
|
|
|
+ if (authcUlrs != null && authcUlrs.length > 0) {
|
|
|
+ for (String authc : authcUlrs) {
|
|
|
+ filterChainDefinitionMap.put(authc, "authc");
|
|
|
+ }
|
|
|
+ }
|
|
|
+ filterChainDefinitionMap.put("/api/v2/**", "anon");
|
|
|
+ filterChainDefinitionMap.put("/doc.html", "anon");
|
|
|
+ filterChainDefinitionMap.put("/v2/api-docs", "anon");
|
|
|
+ filterChainDefinitionMap.put("/configuration/ui", "anon");
|
|
|
+ filterChainDefinitionMap.put("/swagger-resources/**", "anon");
|
|
|
+ filterChainDefinitionMap.put("/configuration/security", "anon");
|
|
|
+ filterChainDefinitionMap.put("/swagger-ui.html", "anon");
|
|
|
+ filterChainDefinitionMap.put("/webjars/**", "anon");
|
|
|
+ filterChainDefinitionMap.put("/swagger-resources/configuration/ui", "anon");
|
|
|
+// filterChainDefinitionMap.put("/**", "authc");
|
|
|
+
|
|
|
+ Map<String, Filter> filters=new HashMap<>();
|
|
|
+// filters.put("authc", new ShiroLoginFilter());
|
|
|
+ //配置过滤器
|
|
|
+ factoryBean.setFilters(filters);
|
|
|
+ factoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
|
|
|
+ return factoryBean;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 注册shiro的委托过滤器,相当于之前在web.xml里面配置的
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Bean
|
|
|
+ public FilterRegistrationBean<DelegatingFilterProxy> delegatingFilterProxy() {
|
|
|
+ FilterRegistrationBean<DelegatingFilterProxy> filterRegistrationBean = new FilterRegistrationBean<DelegatingFilterProxy>();
|
|
|
+ DelegatingFilterProxy proxy = new DelegatingFilterProxy();
|
|
|
+ proxy.setTargetFilterLifecycle(true);
|
|
|
+ proxy.setTargetBeanName(SHIRO_FILTER);
|
|
|
+ filterRegistrationBean.setFilter(proxy);
|
|
|
+ return filterRegistrationBean;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 核心安全事务管理器
|
|
|
+ * 配置SecurityManager
|
|
|
+ */
|
|
|
+ @Bean("securityManager")
|
|
|
+ public SecurityManager securityManager() {
|
|
|
+ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
|
|
|
+ // 设置realm.
|
|
|
+ securityManager.setRealm(userRealm());
|
|
|
+ // 自定义缓存实现 使用redis
|
|
|
+ securityManager.setCacheManager(cacheManager());
|
|
|
+ // 自定义session管理 使用redis
|
|
|
+ securityManager.setSessionManager(sessionManager());
|
|
|
+ return securityManager;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * cacheManager 缓存 redis实现
|
|
|
+ * 使用的是shiro-redis开源插件
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ public RedisCacheManager cacheManager() {
|
|
|
+ RedisCacheManager redisCacheManager = new RedisCacheManager();
|
|
|
+ redisCacheManager.setRedisManager(redisManager());
|
|
|
+ //redis中针对不同用户缓存
|
|
|
+ redisCacheManager.setPrincipalIdFieldName("id");
|
|
|
+ //用户权限信息缓存时间 秒(12h)
|
|
|
+ redisCacheManager.setExpire(43200);
|
|
|
+
|
|
|
+ return redisCacheManager;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 配置shiro redisManager
|
|
|
+ * 使用的是shiro-redis开源插件
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Bean
|
|
|
+ public RedisManager redisManager() {
|
|
|
+// RedisManager redisManager =myRedisManager;
|
|
|
+ RedisManager redisManager = new RedisManager();
|
|
|
+ redisManager.setHost(redisHost+":"+redisPort);
|
|
|
+ redisManager.setDatabase(redisDB);
|
|
|
+ redisManager.setPassword(redisPwd);
|
|
|
+ return redisManager;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * RedisSessionDAO shiro sessionDao层的实现 通过redis
|
|
|
+ * 使用的是shiro-redis开源插件
|
|
|
+ */
|
|
|
+ @Bean
|
|
|
+ public RedisSessionDAO redisSessionDAO() {
|
|
|
+ RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
|
|
|
+ redisSessionDAO.setRedisManager(redisManager());
|
|
|
+ redisSessionDAO.setKeyPrefix("YT_SESSION_CACHE_");
|
|
|
+ return redisSessionDAO;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 声明凭证匹配器
|
|
|
+ */
|
|
|
+ @Bean("credentialsMatcher")
|
|
|
+ public HashedCredentialsMatcher hashedCredentialsMatcher() {
|
|
|
+ HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
|
|
|
+ credentialsMatcher.setHashAlgorithmName(hashAlgorithmName);
|
|
|
+ credentialsMatcher.setHashIterations(hashIterations);
|
|
|
+ return credentialsMatcher;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 声明userRealm
|
|
|
+ */
|
|
|
+ @Bean("userRealm")
|
|
|
+ public UserRealm userRealm() {
|
|
|
+ UserRealm userRealm = new UserRealm();
|
|
|
+ // 注入凭证匹配器
|
|
|
+ userRealm.setCredentialsMatcher(hashedCredentialsMatcher());
|
|
|
+ //启用身份验证缓存,即缓存AuthenticationInfo信息,默认false
|
|
|
+ userRealm.setAuthenticationCachingEnabled(true);
|
|
|
+ //缓存AuthenticationInfo信息的缓存名称 在ehcache-shiro.xml中有对应缓存的配置
|
|
|
+ userRealm.setAuthenticationCacheName("authenticationCache");
|
|
|
+ //启用授权缓存,即缓存AuthorizationInfo信息,默认false
|
|
|
+ userRealm.setAuthorizationCachingEnabled(true);
|
|
|
+ //缓存AuthorizationInfo信息的缓存名称 在ehcache-shiro.xml中有对应缓存的配置
|
|
|
+ userRealm.setAuthorizationCacheName("authorizationCache");
|
|
|
+ return userRealm;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 配置保存sessionId的cookie
|
|
|
+ * 注意:这里的cookie 不是上面的记住我 cookie 记住我需要一个cookie session管理 也需要自己的cookie
|
|
|
+ * 默认为: JSESSIONID 问题: 与SERVLET容器名冲突,重新定义为sid
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Bean("sessionIdCookie")
|
|
|
+ public SimpleCookie sessionIdCookie(){
|
|
|
+ //这个参数是cookie的名称
|
|
|
+ SimpleCookie simpleCookie = new SimpleCookie("sid");
|
|
|
+ //setcookie的httponly属性如果设为true的话,会增加对xss防护的安全系数。它有以下特点:
|
|
|
+
|
|
|
+ //setcookie()的第七个参数
|
|
|
+ //设为true后,只能通过http访问,javascript无法访问
|
|
|
+ //防止xss读取cookie
|
|
|
+// simpleCookie.setHttpOnly(true);
|
|
|
+ simpleCookie.setPath("/");
|
|
|
+ //maxAge=-1表示浏览器关闭时失效此Cookie
|
|
|
+ simpleCookie.setMaxAge(-1);
|
|
|
+ return simpleCookie;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 配置会话管理器,设定会话超时及保存
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Bean("sessionManager")
|
|
|
+ public SessionManager sessionManager() {
|
|
|
+ DefaultWebSessionManager sessionManager = new DefaultWebSessionManager();
|
|
|
+ sessionManager.setSessionIdCookie(sessionIdCookie());
|
|
|
+ sessionManager.setSessionDAO(redisSessionDAO());
|
|
|
+ sessionManager.setCacheManager(cacheManager());
|
|
|
+
|
|
|
+ //全局会话超时时间(单位毫秒),默认30分钟 1800000
|
|
|
+ sessionManager.setGlobalSessionTimeout(28800000);//8*60*60*1000 8个小时
|
|
|
+ //是否开启删除无效的session对象 默认为true
|
|
|
+ sessionManager.setDeleteInvalidSessions(true);
|
|
|
+ //是否开启定时调度器进行检测过期session 默认为true
|
|
|
+ sessionManager.setSessionValidationSchedulerEnabled(true);
|
|
|
+ //设置session失效的扫描时间, 清理用户直接关闭浏览器造成的孤立会话 默认为 1个小时
|
|
|
+ //设置该属性 就不需要设置 ExecutorServiceSessionValidationScheduler 底层也是默认自动调用ExecutorServiceSessionValidationScheduler
|
|
|
+ //暂时设置为 5秒 用来测试
|
|
|
+ sessionManager.setSessionValidationInterval(28800000);//8*60*60*1000 8个小时
|
|
|
+ //取消url 后面的 JSESSIONID
|
|
|
+ sessionManager.setSessionIdUrlRewritingEnabled(false);
|
|
|
+ return sessionManager;
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 加入注解的使用,不加入这个注解不生效
|
|
|
+ * @param securityManager
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Bean
|
|
|
+ public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) {
|
|
|
+ AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
|
|
|
+ authorizationAttributeSourceAdvisor.setSecurityManager(securityManager);
|
|
|
+ return authorizationAttributeSourceAdvisor;
|
|
|
+ }
|
|
|
+ /**
|
|
|
+ * 加入注解的使用,不加入这个注解不生效
|
|
|
+ * @param
|
|
|
+ * @return
|
|
|
+ */
|
|
|
+ @Bean
|
|
|
+ public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
|
|
|
+ DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
|
|
|
+ advisorAutoProxyCreator.setProxyTargetClass(true);
|
|
|
+ return advisorAutoProxyCreator;
|
|
|
+ }
|
|
|
+}
|