package com.yuanchu.limslaboratory.shiro.config; import com.yuanchu.limslaboratory.shiro.filter.JwtFilter; import com.yuanchu.limslaboratory.shiro.MultiRealmAuthenticator; import com.yuanchu.limslaboratory.shiro.realm.JwtRealm; import com.yuanchu.limslaboratory.shiro.realm.ShiroRealm; import com.yuanchu.limslaboratory.shiro.utils.JwtCredentialsMatcher; import org.apache.shiro.authc.credential.CredentialsMatcher; import org.apache.shiro.authc.credential.HashedCredentialsMatcher; import org.apache.shiro.authc.pam.AuthenticationStrategy; import org.apache.shiro.authc.pam.FirstSuccessfulStrategy; import org.apache.shiro.authc.pam.ModularRealmAuthenticator; import org.apache.shiro.authz.Authorizer; import org.apache.shiro.authz.ModularRealmAuthorizer; import org.apache.shiro.crypto.hash.Md5Hash; import org.apache.shiro.mgt.DefaultSessionStorageEvaluator; import org.apache.shiro.mgt.DefaultSubjectDAO; import org.apache.shiro.mgt.SecurityManager; import org.apache.shiro.mgt.SessionStorageEvaluator; import org.apache.shiro.realm.Realm; 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.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import javax.servlet.Filter; import java.util.*; @Configuration public class ShiroConfig { /** * 不向 Spring容器中注册 JwtFilter Bean,防止 Spring 将 JwtFilter 注册为全局过滤器 * 全局过滤器会对所有请求进行拦截,而本例中只需要拦截除 /login 和 /logout 外的请求 * 另一种简单做法是:直接去掉 jwtFilter()上的 @Bean 注解 */ @Bean public FilterRegistrationBean registration(JwtFilter filter) { FilterRegistrationBean registration = new FilterRegistrationBean(filter); registration.setEnabled(false); return registration; } //ShiroFilter过滤所有请求 @Bean public ShiroFilterFactoryBean getShiroFilterFactoryBean(SecurityManager securityManager) { ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //给ShiroFilter配置安全管理器 shiroFilterFactoryBean.setSecurityManager(securityManager); // 添加 jwt 专用过滤器,拦截除 /login 和 /logout 外的请求 Map filterMap = new LinkedHashMap<>(); filterMap.put("jwtFilter", new JwtFilter()); shiroFilterFactoryBean.setFilters(filterMap); //配置系统公共资源 Map map = new HashMap(); // swagger放行 map.put("/doc.html", "anon"); map.put("/webjars/**/**", "anon"); map.put("/swagger-resources", "anon"); map.put("/api-docs", "anon"); map.put("/v3/**", "anon"); map.put("/user/login/**","anon");//表示这个为公共资源 一定是在受限资源上面 // map.put("/**","jwtFilter");//表示这个资源需要认证和授权 shiroFilterFactoryBean.setFilterChainDefinitionMap(map); return shiroFilterFactoryBean; } /** * 配置 ModularRealmAuthenticator */ @Bean public ModularRealmAuthenticator authenticator() { ModularRealmAuthenticator authenticator = new MultiRealmAuthenticator(); // 设置多 Realm的认证策略,默认 AtLeastOneSuccessfulStrategy AuthenticationStrategy strategy = new FirstSuccessfulStrategy(); authenticator.setAuthenticationStrategy(strategy); return authenticator; } /** * 禁用session, 不保存用户登录状态。保证每次请求都重新认证 */ @Bean protected SessionStorageEvaluator sessionStorageEvaluator() { DefaultSessionStorageEvaluator sessionStorageEvaluator = new DefaultSessionStorageEvaluator(); sessionStorageEvaluator.setSessionStorageEnabled(false); return sessionStorageEvaluator; } /** * 配置 SecurityManager:权限管理器 */ @Bean public DefaultWebSecurityManager securityManager() { DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 1.身份验证器 securityManager.setAuthenticator(authenticator()); // 2.管理Realm List realms = new ArrayList(16); realms.add(JwtRealm()); realms.add(shiroRealm()); securityManager.setRealms(realms); // 配置多个realm // 3.关闭shiro自带的session DefaultSubjectDAO subjectDAO = new DefaultSubjectDAO(); subjectDAO.setSessionStorageEvaluator(sessionStorageEvaluator()); securityManager.setSubjectDAO(subjectDAO); return securityManager; } // 创建自定义Realm @Bean public Realm shiroRealm() { ShiroRealm realm = new ShiroRealm(); // HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher(); //// //设置使用MD5加密算法 //// credentialsMatcher.setHashAlgorithmName(Md5Hash.ALGORITHM_NAME); //// //散列次数 //// credentialsMatcher.setHashIterations(1024); // realm.setCredentialsMatcher(credentialsMatcher); return realm; } @Bean public Realm JwtRealm(){ JwtRealm jwtRealm = new JwtRealm(); // 设置加密算法 CredentialsMatcher credentialsMatcher = new JwtCredentialsMatcher(); // 设置加密次数 jwtRealm.setCredentialsMatcher(credentialsMatcher); return jwtRealm; } // 以下三中bean通用,固定配置 /** * 交由 Spring 来自动地管理 Shiro-Bean 的生命周期 */ @Bean public static LifecycleBeanPostProcessor getLifecycleBeanPostProcessor() { return new LifecycleBeanPostProcessor(); } /** * 为 Spring-Bean 开启对 Shiro 注解的支持 */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(SecurityManager securityManager) { AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } /** * 开启AOP方法级权限检查 */ @Bean public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() { DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator(); advisorAutoProxyCreator.setProxyTargetClass(true); return advisorAutoProxyCreator; } }