由于Shiro filterChainDefinitions中 roles默认是and, admin= user,roles[system,general]
比如:roles[system,general] ,表示同时需要“system”和“general” 2个角色(权限)才通过认证,缺一不可。
但是在实际业务中,一个端口往往同时对几个角色开放。比如管理员账号拥有访问所有端口的权限。那么此时的and显然是不合时宜的,与之替代的是or
一、重新实现AuthorizationFilter类
import org.apache.shiro.subject.Subject; import org.apache.shiro.web.filter.authz.AuthorizationFilter; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; /** * @Auther: lanhaifeng * @Date: 2019/4/18 0018 17:40 * @Description:支持多角色验证 * 由于Shiro filterChainDefinitions中 roles默认是and, * = user,roles[system,general] * 比如:roles[system,general] ,表示同时需要“system”和“general” 2个角色才通过认证 * 但是在实际业务中,一个端口的权限往往对多个角色开放(比如管理员可以使用一切权利) */ public class MyRolesAuthorizationFilter extends AuthorizationFilter{ @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { Subject subject = getSubject(request, response); String[] rolesArray = (String[]) mappedValue; //没有权限访问 if (rolesArray == null || rolesArray.length == 0) { return true; } for (int i = 0; i < rolesArray.length; i++) { //若当前用户是rolesArray中的任何一个,则有权限访问 if (subject.hasRole(rolesArray[i])) { return true; } } return false; } }
二、在ShiroConfig引用,其实spring boot集成shiro也就这两步,加上自定义权限验证 和自定义登录验证。
import org.apache.shiro.authc.credential.HashedCredentialsMatcher; 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.session.mgt.DefaultWebSessionManager; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.handler.SimpleMappingExceptionResolver; import javax.servlet.Filter; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.Map; import java.util.Properties; @Configuration public class ShiroConfig { @Bean public ShiroFilterFactoryBean shirFilter(DefaultWebSecurityManager securityManager) { //System.out.println("ShiroConfiguration.shirFilter()"); ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); shiroFilterFactoryBean.setSecurityManager(securityManager); //添加自定义验证方法,注意这个Filter继承javax.servlet.Filter Map<String, Filter> filterMap=new HashMap<>(); filterMap.put("rolesOr",roleFilter()); shiroFilterFactoryBean.setFilters(filterMap); //拦截器. Map<String,String> filterChainDefinitionMap = new LinkedHashMap<String,String>(); // 配置不会被拦截的链接 顺序判断 filterChainDefinitionMap.put("/static/**", "anon"); filterChainDefinitionMap.put("/gif/**", "anon"); //配置退出 过滤器,其中的具体的退出代码Shiro已经替我们实现了 filterChainDefinitionMap.put("/sanyi/logout", "logout"); //<!-- 过滤链定义,从上向下顺序执行,一般将/**放在最为下边 -->:这是一个坑呢,一不小心代码就不好使了; //<!-- authc:所有url都必须认证通过才可以访问; anon:所有url都都可以匿名访问--> filterChainDefinitionMap.put("/sanyi/index", "anon");/*swagger*/ filterChainDefinitionMap.put("/swagger-ui.html", "anon"); filterChainDefinitionMap.put("/swagger-resources/**", "anon"); filterChainDefinitionMap.put("/v2/**", "anon"); filterChainDefinitionMap.put("/webjars/**", "anon"); /*business业务端(1管理员,3业务员)*/ filterChainDefinitionMap.put("/contract/base/**", "authc,rolesOr[1,3]");
/*其他,一定要采取白名单*/ filterChainDefinitionMap.put("/**", "authc"); // 如果不设置默认会自动寻找Web工程根目录下的"/login"页面 shiroFilterFactoryBean.setLoginUrl("/sanyi/index"); // 登录成功后要跳转的链接 shiroFilterFactoryBean.setSuccessUrl("/"); //未授权界面; shiroFilterFactoryBean.setUnauthorizedUrl("/sanyi/nopermission"); shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean; } @Bean public MyRolesAuthorizationFilter roleFilter(){ MyRolesAuthorizationFilter roleFilter=new MyRolesAuthorizationFilter(); return roleFilter; } /** * 密码凭证匹配器 * (由于我们的密码校验交给Shiro的SimpleAuthenticationInfo进行处理了 * ) * @return */ @Bean public HashedCredentialsMatcher hashedCredentialsMatcher(){ HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); hashedCredentialsMatcher.setHashAlgorithmName("md5");//散列算法:这里使用MD5算法; hashedCredentialsMatcher.setHashIterations(10);//散列的次数10哈哈; return hashedCredentialsMatcher; } /** * 身份认证realm; (这个需要自己写,账号密码校验;权限等) * @return */ @Bean public MyShiroRealm myShiroRealm(){ MyShiroRealm myShiroRealm = new MyShiroRealm(); myShiroRealm.setCredentialsMatcher(hashedCredentialsMatcher()); return myShiroRealm; } /** * 会话管理器 * @return */ @Bean public DefaultWebSessionManager sessionManager(){ DefaultWebSessionManager sessionManager=new DefaultWebSessionManager(); sessionManager.setGlobalSessionTimeout(1800000);//单位是ms return sessionManager; } @Bean public DefaultWebSecurityManager securityManager(){ DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setRealm(myShiroRealm()); securityManager.setSessionManager(sessionManager()); return securityManager; } /** * 开启shiro aop注解支持. * 使用代理方式;所以需要开启代码支持; * @param securityManager * @return */ @Bean public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(DefaultWebSecurityManager securityManager){ AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor(); authorizationAttributeSourceAdvisor.setSecurityManager(securityManager); return authorizationAttributeSourceAdvisor; } @Bean(name="simpleMappingExceptionResolver") public SimpleMappingExceptionResolver createSimpleMappingExceptionResolver() { SimpleMappingExceptionResolver r = new SimpleMappingExceptionResolver(); Properties mappings = new Properties(); mappings.setProperty("DatabaseException", "databaseError");//数据库异常处理 mappings.setProperty("UnauthorizedException","403"); r.setExceptionMappings(mappings); // None by default r.setDefaultErrorView("error"); // No default r.setExceptionAttribute("exception"); // Default is "exception" //r.setWarnLogCategory("example.MvcLogger"); // No default return r; } }