/** * MIT License * Copyright (c) 2018 yadong.zhang * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. */ package com.zyd.shiro.framework.config; import com.zyd.shiro.business.service.ShiroService; import com.zyd.shiro.business.shiro.credentials.RetryLimitCredentialsMatcher; import com.zyd.shiro.business.shiro.realm.ShiroRealm; import com.zyd.shiro.framework.property.RedisProperties; import com.zyd.shiro.framework.redis.CustomRedisManager; import org.apache.shiro.codec.Base64; 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.CookieRememberMeManager; 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.Qualifier; import org.springframework.beans.factory.config.MethodInvokingFactoryBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.DependsOn; import org.springframework.core.annotation.Order; import java.util.Map; /** * Shiro配置类 * * @author yadong.zhang (yadong.zhang0415(a)gmail.com) * @version 1.0 * @website https://www.zhyd.me * @date 2018/4/24 14:37 * @since 1.0 */ @Configuration @Order(-1) public class ShiroConfig { @Autowired private ShiroService shiroService; @Autowired private RedisProperties redisProperties; @Bean public MethodInvokingFactoryBean methodInvokingFactoryBean(SecurityManager securityManager){ MethodInvokingFactoryBean bean = new MethodInvokingFactoryBean(); bean.setStaticMethod("org.apache.shiro.SecurityUtils.setSecurityManager"); bean.setArguments(securityManager); return bean; } @Bean(name = "lifecycleBeanPostProcessor") public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } /** * ShiroFilterFactoryBean 处理拦截资源文件问题。 * 注意:单独一个ShiroFilterFactoryBean配置是或报错的,因为在 * 初始化ShiroFilterFactoryBean的时候需要注入:SecurityManager * Filter Chain定义说明 * 1、一个URL可以配置多个Filter,使用逗号分隔 * 2、当设置多个过滤器时,全部验证通过,才视为通过 * 3、部分过滤器可指定参数,如perms,roles */ @Bean(name = "shiroFilter") public ShiroFilterFactoryBean shirFilter(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 必须设置 SecurityManager shiroFilterFactoryBean.setSecurityManager(securityManager); // 如果不设置默认会自动寻找Web工程根目录下的"/login.jsp"页面 shiroFilterFactoryBean.setLoginUrl("/passport/login/"); // 登录成功后要跳转的链接 shiroFilterFactoryBean.setSuccessUrl("/index"); // 未授权界面; shiroFilterFactoryBean.setUnauthorizedUrl("/error/403"); // 配置数据库中的resource Map<String, String> filterChainDefinitionMap = shiroService.loadFilterChainDefinitions(); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean @DependsOn("lifecycleBeanPostProcessor") public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator creator = new DefaultAdvisorAutoProxyCreator(); creator.setProxyTargetClass(true); return creator; } @Bean(name = "securityManager") public SecurityManager securityManager(@Qualifier("shiroRealm") ShiroRealm authRealm) { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 设置realm. securityManager.setRealm(authRealm); securityManager.setCacheManager(redisCacheManager()); // 自定义session管理 使用redis securityManager.setSessionManager(sessionManager()); // 注入记住我管理器 securityManager.setRememberMeManager(rememberMeManager()); return securityManager; } @Bean(name = "shiroRealm") public ShiroRealm shiroRealm(@Qualifier("credentialsMatcher") RetryLimitCredentialsMatcher matcher) { ShiroRealm shiroRealm = new ShiroRealm(); shiroRealm.setCredentialsMatcher(credentialsMatcher()); return shiroRealm; } /** * 凭证匹配器 * (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了 * 所以我们需要修改下doGetAuthenticationInfo中的代码; * ) * * @return */ @Bean(name = "credentialsMatcher") public RetryLimitCredentialsMatcher credentialsMatcher() { return new RetryLimitCredentialsMatcher(); } /** * 开启shiro aop注解支持. * 使用代理方式;所以需要开启代码支持; * * @param securityManager * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } /** * 配置shiro redisManager * 使用的是shiro-redis开源插件 * * @return */ public RedisManager redisManager() { CustomRedisManager redisManager = new CustomRedisManager(); redisManager.setHost(redisProperties.getHost()); redisManager.setPort(redisProperties.getPort()); redisManager.setDatabase(redisProperties.getDatabase()); redisManager.setTimeout(redisProperties.getTimeout()); redisManager.setPassword(redisProperties.getPassword()); return redisManager; } /** * cacheManager 缓存 redis实现 * 使用的是shiro-redis开源插件 * * @return */ @Bean public RedisCacheManager redisCacheManager() { RedisCacheManager redisCacheManager = new RedisCacheManager(); redisCacheManager.setRedisManager(redisManager()); return redisCacheManager; } /** * RedisSessionDAO shiro sessionDao层的实现 通过redis * 使用的是shiro-redis开源插件 */ // @Bean public RedisSessionDAO redisSessionDAO() { RedisSessionDAO redisSessionDAO = new RedisSessionDAO(); redisSessionDAO.setRedisManager(redisManager()); return redisSessionDAO; } /** * shiro session的管理 */ @Bean public DefaultWebSessionManager sessionManager() { DefaultWebSessionManager sessionManager = new DefaultWebSessionManager(); sessionManager.setGlobalSessionTimeout(redisProperties.getExpire() * 1000L); sessionManager.setSessionDAO(redisSessionDAO()); return sessionManager; } /** * cookie对象; * * @return */ public SimpleCookie rememberMeCookie() { // 这个参数是cookie的名称,对应前端的checkbox的name = rememberMe SimpleCookie simpleCookie = new SimpleCookie("rememberMe"); // 记住我cookie生效时间30天 ,单位秒。 注释掉,默认永久不过期 2018-07-15 simpleCookie.setMaxAge(redisProperties.getExpire()); return simpleCookie; } /** * cookie管理对象;记住我功能 * * @return */ public CookieRememberMeManager rememberMeManager() { CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager(); cookieRememberMeManager.setCookie(rememberMeCookie()); //rememberMe cookie加密的密钥 建议每个项目都不一样 默认AES算法 密钥长度(128 256 512 位) cookieRememberMeManager.setCipherKey(Base64.decode("1QWLxg+NYmxraMoxAXu/Iw==")); return cookieRememberMeManager; } }