深入淺出學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,故接下來執行我們自定義的
@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操作的橋樑,以下這張圖很形象的展示了三者的關係。