1. 程式人生 > >深入淺出學Shiro(二)--授權認證

深入淺出學Shiro(二)--授權認證

    授權即訪問控制,它將判斷使用者在應用程式中對資源是否擁有相應的訪問許可權。如,判斷一個使用者有檢視頁面的許可權,編輯資料的許可權,擁有某一按鈕的許可權,以及是否擁有列印的許可權等等。

    認證通過後接受 Shiro授權檢查,授權驗證時,需要判斷當前角色是否擁有該許可權。只有授權通過,才可以訪問受保護 URL 對應的資源,否則跳轉到“未經授權頁面”。

首先來結合一個例項來說明:

shiro認證成功後,跳轉到main.jsp頁面

Main.jsp頁面內容:

<body>
		<ul>
			<li>
				<h2>
					<a target="_self" href="user.do?myjsp">訪問myjsp頁面</a>
				</h2>
			</li>
			<li>
				<h2>
					<a target="_self" href="user.do?notmyjsp">訪問notmyjsp頁面(無權訪問)</a>
				</h2>
			</li>
			<li>
				<h2>
					<a target="_self" href="user.do?visitAdminPage">訪問admin頁面</a>
				</h2>
			</li>
			
			<li>
				<h2>
					<a target="_self" href="user.do?visitByAnnotation">通過註解訪問頁面(無權訪問)</a>
				</h2>
			</li>
		</ul>
	</body>

當點選頁面某個連結時,跳轉到相應的controller

@Controller
@RequestMapping(value="user")
public class UserController {
	/**
	 * 訪問myjsp頁面,有許可權
	 * @return
	 */
	@RequestMapping(params = "myjsp")
	public String home() {
		/*通過SecurityUtils工具類,獲取當前的使用者*/
		Subject currentUser = SecurityUtils.getSubject();
		
		// 回撥 doGetAuthorizationInfo,進行授權驗證
		if(currentUser.isPermitted("user.do?myjsp")){
			return "my";
		}else{
			return "error/noperms";
		}
	}

當程式執行到currentUser.isPermitted方法時,呼叫到publicclass DelegatingSubject implements Subject類的isPermitted方法。

附原始碼:

public boolean isPermitted(String permission) {
        return hasPrincipals() && securityManager.isPermitted(getPrincipals(), permission);
    }


通過上篇部落格我們知道,這時SecurityManager會委託給Realm,故接下來執行我們自定義的

Realm

@Service("monitorRealm")
public class MonitorRealm extends AuthorizingRealm {

	//獲取授權資訊 
	@Override
	protected AuthorizationInfo doGetAuthorizationInfo(
			PrincipalCollection principals) {
		/* 這裡編寫授權程式碼 */
		Set<String> roleNames = new HashSet<String>();
	    Set<String> permissions = new HashSet<String>();
	    roleNames.add("admin");
	    permissions.add("user.do?myjsp");
	    permissions.add("login.do?main");
	    permissions.add("login.do?logout");
	    //對比的過程
		SimpleAuthorizationInfo info = new SimpleAuthorizationInfo(roleNames);
	    info.setStringPermissions(permissions);
		return info;
	}
}

對比的過程中如果存在則正確返回,否則返回error

補充:

結合上篇部落格的配置還想要多說兩句

其一:SpringMVC攔截

這部分配置,是配置SpringMVC的攔截頁面,看了這個配置相信大家也就明白了為什麼我們訪問的頁面要加上.do(user.do?notmyjsp)吧!

<servlet-mapping>
		<servlet-name>springMvc</servlet-name>
		<!-- 只攔截帶do字尾的 -->
		<!-- <url-pattern>*.do</url-pattern> -->
		<!-- 將springmvc的匹配表示式修改為所有的頁面均攔截 -->
		<url-pattern>/</url-pattern> 

</servlet-mapping>

其二:ShiroFilter攔截

這部分配置是配置的ShiroFilter,也就是shiro攔截哪些頁面。

<!-- Shiro主過濾器本身功能十分強大,其強大之處就在於它支援任何基於URL路徑表示式的、自定義的過濾器的執行-->  
	<!-- Shiro Filter -->  
	<filter>
		<filter-name>shiroFilter</filter-name>
		<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
		<init-param>
			<param-name>targetFilterLifecycle</param-name>
			<param-value>true</param-value>
		</init-param>
	</filter>
	<!-- shiro只攔截如下的字尾 -->
	<filter-mapping>
		<filter-name>shiroFilter</filter-name>
		<url-pattern>*.action</url-pattern>
	</filter-mapping>
	<filter-mapping>
		<filter-name>shiroFilter</filter-name>
		<url-pattern>*.do</url-pattern>
	</filter-mapping>
	<filter-mapping>
		<filter-name>shiroFilter</filter-name>
		<url-pattern>*.jsp</url-pattern>
	</filter-mapping>


其三:Shiro過濾鏈的定義(是否需要登入認證)

以下這部分配置,是配置訪問的頁面是否需要驗證,即登入後才可以訪問。舉例說明:訪問字尾名為.action的頁面,我可以直接訪問到,那麼如果我訪問.do的頁面,則會自動跳轉到登入頁,需要我們首先登入後才可以訪問,這些就與我們配置的過濾鏈相關。

<property name="filterChainDefinitions">
			<value>
			 <!-- Shiro 過濾鏈的定義-->   
        <!--此處可配合這篇文章來理解各個過濾連的作用http://blog.csdn.net/jadyer/article/details/12172839-->
				<!-- 
					Anon:不指定過濾器 
					Authc:驗證,這些頁面必須驗證後才能訪問,也就是我們說的登入後才能訪問。
					-->
					 <!--下面value值的第一個'/'代表的路徑是相對於HttpServletRequest.getContextPath()的值來的 -->   
					<!--anon:它對應的過濾器裡面是空的,什麼都沒做,這裡.do和.jsp後面的*表示引數,比方說login.jsp?main這種 -->   
        <!--authc:該過濾器下的頁面必須驗證後才能訪問,它是Shiro內建的一個攔截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter-->   
				
				/login.jsp* = anon
				/login.do* = anon
				/index.jsp*= anon
				/error/noperms.jsp*= anon
				/*.jsp* = authc
				/*.do* = authc
			</value>
		</property>


這些過濾器分為兩組,一組是認證過濾器,一組是授權過濾器。其中anon,authcBasic,auchc,user是第一組,

perms,roles,ssl,rest,port是第二組

可參考:http://blog.csdn.net/hxpjava1/article/details/7035724

擴充套件:

Shiro支援三種方式實現授權過程:

編碼實現

註解實現

JSPTaglig實現

程式設計式:通過寫if/else授權程式碼塊完成(以上例項即使用程式設計式完成): 

Subject subject = SecurityUtils.getSubject();  
if(subject.hasRole(“admin”)) {  
    //有許可權  
} else {  
    //無許可權  
}   


註解式:通過在執行的Java方法上放置相應的註解完成:

@RequiresRoles("admin")  
public void hello() {  
    //有許可權  
}   

沒有許可權將丟擲相應的異常;

JSP標籤:在JSP/GSP頁面通過相應的標籤完成: 

<shiro:hasPermission name="user:create">  
	<a href="createUser.jsp">Create a new User</a>  
</shiro:hasPermission>  


總結:

    無論是Shiro的登入認證還是授權,其實都是結合Subject,SecurityManager和Realms這三者的關係來實現的,理解了三者的關係Shiro也就學會了。Subject,當前使用者;SecurityManager,外觀的作用,其內部為我們封裝了實現好的功能;Realms,Shiro和真實Dao操作的橋樑,以下這張圖很形象的展示了三者的關係。