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,如下列表
在這裏插入圖片描述
在沒有自定義的情況下,默認如
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角色的刪除權限纔可以訪問,如下配置

    <!-- 自定義登錄驗證過濾器 -->
    <bean id="loginCheckPermissionFilter" class="com.bug.filter.LoginCheckPermissionFilter"></bean>
    
    <!-- 自定義權限認證器 -->
    <bean id="permissionsAuthorizationFilter" class="com.bug.filter.PermissionsAuthorizationFilter"></bean>
   
    <!-- Shiro的web過濾器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    	<property name="securityManager" ref="securityManager"></property>
    	<!-- <property name="unauthorizedUrl" value="/index.jsp"></property> -->
    	<property name="filters">
    		<map>
    			<entry key="authc" value-ref="loginCheckPermissionFilter"></entry>
    			<entry key="perms" value-ref="permissionsAuthorizationFilter"></entry>
    		</map>
    	</property>
    	<property name="filterChainDefinitions">
    		<value>
                /user/queryUserInfo = authc
                /user/deleteUser/** = perms[USER:DELETE]
    		</value>
    	</property>
    </bean>

上面的配置, 在filterChainDefinitions中配置了/user/deleteUser/**=perms[USER:DELETE],表示需要有USER角色的刪除權限才能訪問,而perms又指向了filters中定義的perms,該perms使用permissionsAuthorizationFilter處理,從而覆蓋了默認的 org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter,默認的PermissionsAuthorizationFilter,繼承了AuthorizationFilter,並重寫isAccessAllowed方法,源碼如下
在這裏插入圖片描述

因此我們自定義的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<String> responseVO = new ResponseVO<String>();
		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<String> roles = new HashSet<String>();
		Set<String> stringPermissions = new HashSet<String>();
		roles.add("USER");
		stringPermissions.add("USER:DELETE");//角色:權限
		
		info.setRoles(roles);
		info.setStringPermissions(stringPermissions);
		
		return info;
	}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章