Shiro权限控制(二):自定义Filter

一、目标
通过自定义Filter实现权限配置,如某个URL需要某个角色的某个权限才能操作

二、前言
在前面的一篇博文《Shiro权限控制(一):Spring整合Shiro》中,介绍了如何在Spring MVC中整合Shiro权限框架,其中在spring-shiro-web.xml配置文件中,有个 id="shiroFilter"的bean org.apache.shiro.spring.web.ShiroFilterFactoryBean,在这个bean中,定义了URL的访问规则,这些访问规则,就是通过Shiro的Filter实现的,下面就来介绍如何实现自定义的Filter来实现访问控制

三、Shiro内置Filter
在Shiro框架中,已经提供了很多内置的Filter,其中常见的有anon,authc,perms,roles,如下列表
Shiro权限控制(二):自定义Filter_第1张图片
在没有自定义的情况下,默认如
anon表示使用org.apache.shiro.web.filter.authc.AnonymousFilter处理
authc表示使用org.apache.shiro.web.filter.authc.FormAuthenticationFilter处理

如果想实现自定义Filter,就需要覆盖Shiro中内置的Filter,如何实现呢?

四、自定义Filter

上面说到在spring-shiro-web.xml配置文件中,有个 id="shiroFilter"的bean org.apache.shiro.spring.web.ShiroFilterFactoryBean,在这个Bean中有两个非常重要的属性filterChainDefinitions和filters

filterChainDefinitions:定义了URL的访问规则,从源码中可以看到,这些规则最后存储在ShiroFilterFactoryBean的filterChainDefinitionMap属性中,key值是URL规则,value值是filter的引用,表示使用哪些Filter处理URL

filters:属性filters是一个Map集合,key值是Filter Name,value值是具体的Filter类

下面我们自定义一个perms的Filter,来处理 /user/deleteUser/**,需要USER角色的删除权限才可以访问,如下配置

    
    
    
    
    
   
    
    
    	
    	
    	
    		
    			
    			
    		
    	
    	
    		
                /user/queryUserInfo = authc
                /user/deleteUser/** = perms[USER:DELETE]
    		
    	
    

上面的配置, 在filterChainDefinitions中配置了/user/deleteUser/**=perms[USER:DELETE],表示需要有USER角色的删除权限才能访问,而perms又指向了filters中定义的perms,该perms使用permissionsAuthorizationFilter处理,从而覆盖了默认的 org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter,默认的PermissionsAuthorizationFilter,继承了AuthorizationFilter,并重写isAccessAllowed方法,源码如下
Shiro权限控制(二):自定义Filter_第2张图片

因此我们自定义的permissionsAuthorizationFilter,也需要继承AuthorizationFilter,并重写isAccessAllowed方法,如下

package com.bug.filter;

import java.io.IOException;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletResponse;

import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.authz.AuthorizationFilter;

import com.bug.common.JSONParseUtils;
import com.bug.model.common.ResponseVO;

/**
 * 权限校验过滤器
 * @author longwentao
 *
 */
public class PermissionsAuthorizationFilter extends AuthorizationFilter {

	@Override
	protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception {
		Subject subject = getSubject(request, response);
		String[] perms = (String[]) mappedValue;

		boolean isPermitted = true;
		if (perms != null && perms.length > 0) {
			if (perms.length == 1) {
				if (!subject.isPermitted(perms[0])) {
					isPermitted = false;
				}
			} else {
				if (!subject.isPermittedAll(perms)) {
					isPermitted = false;
				}
			}
		}
		return isPermitted;
	}

	@Override
	protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws IOException {
		HttpServletResponse httpServletResponse = (HttpServletResponse) response;
		httpServletResponse.setHeader("Content-Type", "application/json;charset=UTF-8");
		ResponseVO responseVO = new ResponseVO();
		responseVO.setStatus(ResponseVO.failCode);
		responseVO.setMessage("没有权限,请联系管理员");
		
		byte[] bytes = JSONParseUtils.readJson2Byte(responseVO);
		httpServletResponse.getOutputStream().write(bytes);
		return false;
	}
}

到此,自定义Filter已经完成了,下面补充一下如何将权限给Shiro框架

可以在用户身份证验证通过后,从DB中获得用户的角色权限放到AuthorizationInfo中,并返回给Shiro框架,该代码是在自定义的Realm中实现的,可参考前面的文章《Shiro权限控制之整合Spring(一)》

@Override
	protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
		String username = (String)principals.getPrimaryPrincipal();
		if(username == null) {
			throw new BugException("未登录");
		}
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
		Set roles = new HashSet();
		Set stringPermissions = new HashSet();
		roles.add("USER");
		stringPermissions.add("USER:DELETE");//角色:权限
		
		info.setRoles(roles);
		info.setStringPermissions(stringPermissions);
		
		return info;
	}

你可能感兴趣的:(Shiro)