1. 程式人生 > >【Shiro許可權管理】17.Shiro許可權註解

【Shiro許可權管理】17.Shiro許可權註解

注:該系列所有測試均在之前建立的Shiro3的Web工程的基礎上。
前面我們講解了Shiro的標籤屬性,下面我們來講解Shiro的有關許可權的註解屬性。

Shiro的註解是使用在相應的Java類的方法上,當用戶不滿足註解的要求時,是無法執行
方法內部邏輯的。這相當於在程式碼層做了許可權校驗。
Shiro的註解可以放置在Controller層對應的方法上,也可以放置在Service層對應的方法上。

Shiro的註解型別大致如下:
(1)@RequiresAuthentication
表示當前Subject已經通過login進行了身份驗證;即Subject.isAuthenticated()返回true。

(2)@RequiresUser
表示當前Subject已經進行身份驗證或者通過“記住我”登入。

(3)@RequiresGuest

表示當前Subject沒有身份驗證或者通過“記住我”登入過,即是 遊客身份。

(4)@RequiresRoles(value={"admin","user"},logical=Logical.OR)
表示當前Subject需要角色admin和user。

(5)@RequiresPermissions(value={"user:a","user:b"},logical=Logical.OR)
表示當前Subject需要許可權user:a或user:b。

下面我們在原來Shiro3工程的基礎上測試幾個註解。
首先在工程中建立一個Service:
package com.test.shiro.services;
import java.text.SimpleDateFormat;
import java.util.Date;
public class ShiroService {
    public void testMethod(){
    	System.out.println("testMethod,time:"
    			+new SimpleDateFormat("yyy-MM-dd HH:mm:ss").format(new  Date()));
    }
}
在其中編寫了名為“testMethod”的方法,在其中列印呼叫方法的當前時間。
然後將這個Service注入Spring的IOC容器,即在applicationContext.xml中新增該Service對應的bean:
<bean id="shiroService" class="com.test.shiro.services.ShiroService">
</bean>

然後在原來的登入Controller中注入該Service,並建立一個testShiroAnnocation服務:
package com.test.shiro.controller;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import com.test.shiro.services.ShiroService;

@Controller
@RequestMapping("userAuth")
public class ShiroLoginController {
	
	@Autowired
	private ShiroService shiroService;
	
	@RequestMapping("/testShiroAnnocation")
	private String testShiroAnnocation(){
		shiroService.testMethod();
		return "redirect:/list.jsp";
	}
	
	@RequestMapping("login")
	public String login(String username,String password){
		//獲取當前的Subject
        	Subject currentUser = SecurityUtils.getSubject();
        	//測試當前使用者是否已經被認證(即是否已經登入)
        	if (!currentUser.isAuthenticated()) {
        		//將使用者名稱與密碼封裝為UsernamePasswordToken物件
            		UsernamePasswordToken token = 
				new UsernamePasswordToken(username, password);
            		token.setRememberMe(true);//記錄使用者
            		try {
                		currentUser.login(token);//呼叫Subject的login方法執行登入
            		} catch (AuthenticationException e) {//所有認證時異常的父類
                		System.out.println("登入失敗:"+e.getMessage());
            		} 
        	}
		return "redirect:/list.jsp";
	}
}

在list.jsp介面新增一個觸發“testShiroAnnocation”服務的超連結:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%@ taglib prefix="shiro" uri="http://shiro.apache.org/tags" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
  <head>
    <title>首頁</title>
  </head>
  <body>
     登入成功!歡迎<shiro:principal/>訪問首頁O(∩_∩)O
   <a href="userAuth/logout">登出</a>
   
   <br/><br/>
   <!-- “testShiroAnnocation”服務的超連結 -->
   <a href="userAuth/testShiroAnnocation">Test ShiroAnnocation</a>
   
   <shiro:hasRole name="admin">
   <br/><br/>
   <a href="admin.jsp">Admin Page</a>
   </shiro:hasRole>
   
   <shiro:hasRole name="user">
   <br/><br/>
   <a href="User.jsp">User Page</a>
   </shiro:hasRole>
   
  </body>
</html>

此時我們沒有給testShiroAnnocation服務加任何許可權註解,所以是可以自由訪問的:

點選超連結之後,MyEclipse的控制檯顯示了執行方法的時間:



下面我們對Service的testMethod方法新增一個控制權限的註解“@RequiresRoles”:
package com.test.shiro.services;
import java.text.SimpleDateFormat;
import java.util.Date;
import org.apache.shiro.authz.annotation.RequiresRoles;
public class ShiroService {
    @RequiresRoles({"admin"})
    public void testMethod(){
    	System.out.println("testMethod,time:"
    			+new SimpleDateFormat("yyy-MM-dd HH:mm:ss").format(new  Date()));
    }
}
上面的註解控制只有當用戶角色包含“admin”時,才會執行testMethod方法。
下面我們使用沒有admin角色的jack使用者登入:

然後點選“Test ShiroAnnocation”超連結時,沒有顯示執行方法時間,而是丟擲了異常:

改異常表明了使用者沒有“admin”的角色資訊。
上面的異常可以使用Spring的“宣告式異常”來跳轉至友好提示頁面,這裡就不進行處理了。

最後需要注意的是:
在日常開發時,往往會在Service層新增“@Transactional”註解,為的是當Service傳送資料庫異常時,
所有資料庫操作可以回滾。
當在Service層新增“@Transactional”註解後,執行Service方法前,會開啟事務。此時的Service已經是
一個代理物件了,此時如果我們將Shiro的許可權註解載入Service層是不合適的,此時需要加到Controller
層。這是因為不能讓Service是“代理的代理”,如果強行注入,會發生型別轉換異常。

以上就是關於Shiro許可權註解的講解。