/**
* 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,普通用户]