shiro----------------3.过滤器
/** * anon(匿名)、logout(登出)、authc(认证) */ @Bean public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager, ShiroService shiroService) { ShiroFilterFactoryBean shiroFilter = new ShiroFilterFactoryBean(); shiroFilter.setSecurityManager(securityManager); shiroFilter.setLoginUrl("/user/no/login"); shiroFilter.setSuccessUrl("/user/success"); shiroFilter.setUnauthorizedUrl("/user/fail"); Map<String, Filter> filterMap = new LinkedHashMap<>(1); //自定义角色过滤器 filterMap.put("roles", rolesAuthorizationFilter()); shiroFilter.setFilters(filterMap); // 过滤链可以使用注解形式实现 shiroFilter.setFilterChainDefinitionMap(shiroService.loadFilterChainDefinitions()); return shiroFilter; } /** * 自定义角色过滤器 */ @Bean public CustomRolesAuthorizationFilter rolesAuthorizationFilter() { return new CustomRolesAuthorizationFilter(); }
1.创建了一个过滤器管理类FilterChainManager,该类主要管理shiro里的过滤器,里面有2个重要的属性
1.1 filters:管理全部过滤器,包括默认的关于身份验证和权限验证的过滤器,这些过滤器分为两组,一组是认证过滤器,有anon,authcBasic,auchc,user,一组是授权过滤器,有perms,roles,ssl,rest,port。同时也包含在xml里filters配置的自定义过滤器。在其它地方使用时都是从过滤器管理类里filters里拿的。且过滤器是单例的,整个Shiro框架只维护每种类型过滤器的单例,可以自己实现过滤器,只需配置对应的过滤链来匹配。
1.2 filterChains:过滤链。shiroService.loadFilterChainDefinitions()这里单独实现过滤链
2.将过滤器管理类设置到PathMatchingFilterChainResolver类里,该类负责路径和过滤器链的解析与匹配。根据url找到过滤器链。
重写一个角色过滤器
/** * 自定义角色授权过滤器 */ public class CustomRolesAuthorizationFilter extends RolesAuthorizationFilter { @Override public boolean isAccessAllowed(ServletRequest req, ServletResponse resp, Object mappedValue) { Subject subject = getSubject(req, resp); 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; } @Override public boolean onPreHandle(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { HttpServletRequest servletRequest = (HttpServletRequest) request; HttpServletResponse servletResponse = (HttpServletResponse) response; boolean isAccess = isAccessAllowed(request, response, mappedValue); if (isAccess) { return true; } servletResponse.setCharacterEncoding("UTF-8"); Subject subject = getSubject(request, response); PrintWriter printWriter = servletResponse.getWriter(); servletResponse.setContentType("application/json;charset=UTF-8"); servletResponse.setHeader("Access-Control-Allow-Origin", servletRequest.getHeader("Origin")); servletResponse.setHeader("Access-Control-Allow-Credentials", "true"); servletResponse.setHeader("Vary", "Origin"); String respStr; if (subject.getPrincipal() == null) { respStr =JSONObject.toJSONString(KeyValue.forbidden("您还未登录,请先登录")); } else { respStr =JSONObject.toJSONString(KeyValue.forbidden("您没有此权限,请联系管理员")); } printWriter.write(respStr); printWriter.flush(); servletResponse.setHeader("content-Length", respStr.getBytes().length + ""); return false; } }
采用编码式配置过滤链
/** * 初始化权限 anon(匿名)、logout(登出)、authc(认证) */ @Override public Map<String, String> loadFilterChainDefinitions() { List<Authority> authorities = authorityMapper.selectAll(); // 权限控制map.从数据库获取 Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); if (!CollectionUtils.isEmpty(authorities)){ for (Authority authority : authorities) { if (StringUtils.isEmpty(authority.getPermission())) { continue; } String uris = authority.getUri(); List<String> uriList = Lists.newArrayList(Splitter.on(",").omitEmptyStrings().trimResults().split(uris)); uriList.forEach(x-> filterChainDefinitionMap.put(x, authority.getPermission())); } } filterChainDefinitionMap.put("/user/no/login", "anon"); filterChainDefinitionMap.put("/user/login", "anon"); filterChainDefinitionMap.put("/user/logout", "anon"); filterChainDefinitionMap.put("/test/*", "anon"); filterChainDefinitionMap.put("/redis/*", "roles[admin]"); filterChainDefinitionMap.put("/**", "authc"); return filterChainDefinitionMap; }
权限存储的格式:roles[admin,普通用户]