Shiro權限控制(三):Shiro註解權限驗證

一、目標

權限配置在數據庫中,通過註解Shiro的註解實現服務的權限驗證

二、前言
在前面的一篇博文中《Shiro權限控制(二):自定義Filter》,我們的權限驗證是配置在shiro配置文件中的,即在spring-shiro-web.xml中的ShiroFilterFactoryBean的filterChainDefinitions屬性中,如下

    <!-- Shiro的web過濾器 -->
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    	<property name="securityManager" ref="securityManager"></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>

如何通過註解的方式,實現權限的驗證呢?請看下面的介紹

三、啓用註解
1、必須在Spring MVC的配置文件中,增加以下配置,啓用Shiro的權限註解功能

    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"
	        depends-on="lifecycleBeanPostProcessor" />
	        
	<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
	        <property name="securityManager" ref="securityManager" />
	</bean>

說明:我的Spring MVC的文件是spring-servlet.xml,該文件必須在web.xml文件中引入

   <servlet>
	 	<servlet-name>springmvc</servlet-name>
	 	<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
	 	<init-param>
	 		<param-name>contextConfigLocation</param-name>
	 		<param-value>classpath:config/spring-servlet.xml</param-value>
	 	</init-param>
	</servlet>
	<servlet-mapping>
		<servlet-name>springmvc</servlet-name>
		<url-pattern>/*</url-pattern>
	</servlet-mapping>

2、在spring-shiro-web.xml文件中增加以下配置

    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"></bean>

通過上面的配置,Shiro的權限註解已經生效,下面來驗證一下

三、驗證

1.創建權限表
分別增加角色表sys_role_t,角色權限表sys_role_perm_t,用戶角色權限關係表user_role_perm_t

在角色表sys_role_t中初始化三個角色,分別爲系統管理員,普通用戶,區域管理員在這裏插入圖片描述

在角色權限表sys_role_perm_t中初始化普通用戶,區域管理員具有增、刪、改、查權限
在這裏插入圖片描述
在用戶角色權限關係表user_role_perm_t中配置user_id=1的用戶,有普通用戶角色的查詢、編輯、新增權限;有區域管理員角色的刪除權限
在這裏插入圖片描述

2.自定義UserShiroRealm
自定義UserShiroRealm,繼承AuthorizingRealm,重寫doGetAuthorizationInfo方法,在方法中查詢用戶的所有權限,並交給Shiro進行權限驗證

    @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>();
		List<UserPermissionVO> list = userService.queryUserPermission(userName);
		for (UserPermissionVO userPermissionVO : list) {
			roles.add(userPermissionVO.getRoleCode());
			stringPermissions.add(userPermissionVO.getPermCodes());
		}
		//roles.add("USER");
		//stringPermissions.add("USER:DELETE");//角色:刪除權限
		info.setRoles(roles);
		info.setStringPermissions(stringPermissions);
		
		return info;
	}

3.編寫服務
服務名稱:增加用戶
權限要求:普通用戶角色的新增權限 或 區域管理員的新增權限纔可訪問

    @ResponseBody
	@RequiresPermissions(value = { "CUSTOMER_USER:ADD","AREA_MANAGER:ADD" },logical=Logical.OR)
	@RequestMapping(value="/addUser",method = RequestMethod.GET)
	public ResponseVO<String> addUser() {
		ResponseVO<String> response = new ResponseVO<String>();
		try {
			response.setMessage("add user success");
		} catch (Exception e) {
			logger.error("add user error:",e);
			response.setStatus(ResponseVO.failCode);
		}
		return response;
	}

logical=Logical.OR 表示或,滿足其中一個權限即可訪問
logical=Logical.AND 表示與,滿足所有權限纔可訪問

未登錄,直接訪問http://localhost:8080/bug.web/user/addUser,報如下錯誤,提示沒有登錄
在這裏插入圖片描述
登錄成功後,再次訪問http://localhost:8080/bug.web/user/addUser,請求成功,如果從數據庫中刪除用戶的 CUSTOMER_USER:ADD權限和AREA_MANAGER:DELETE權限,再次請求時報如下錯誤,提示沒有訪問權限
在這裏插入圖片描述
上面的異常如何處理請看另一篇博文《Shiro權限控制之註解驗證異常處理(四)》

上面只是用到了@RequiresPermissions註解,其他註解如下

四、其他註解說明
@RequiresAuthentication

驗證用戶是否登錄,等同於方法subject.isAuthenticated() 結果爲true時。

@RequiresUser

驗證用戶是否被記憶,user有兩種含義:

一種是成功登錄的(subject.isAuthenticated() 結果爲true);

另外一種是被記憶的(subject.isRemembered()結果爲true)。

@RequiresGuest

驗證是否是一個guest的請求,與@RequiresUser完全相反。

換言之,RequiresUser == !RequiresGuest。

此時subject.getPrincipal() 結果爲null.

@RequiresRoles

例如:@RequiresRoles(“aRoleName”);

void someMethod();

如果subject中有aRoleName角色纔可以訪問方法someMethod。如果沒有這個權限則會拋出異常AuthorizationException。

@RequiresPermissions

例如: @RequiresPermissions({“file:read”, “write:aFile.txt”} )
void someMethod();

要求subject中必須同時含有file:read和write:aFile.txt的權限才能執行方法someMethod()。否則拋出異常AuthorizationException。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章