1. 程式人生 > >Spring專案整合ShiroFilter簡單實現許可權管理

Spring專案整合ShiroFilter簡單實現許可權管理

Shiros是我們開發中常用的用來實現許可權控制的一種工具包,它主要有認證、授權、加密、會話管理、與Web整合、快取等功能。我是從事javaweb工作的,我就經常遇到需要實現許可權控制的專案,之前我們都是靠查詢資料獲取列表拼接展示的,還有的是及時的判斷許可權的問題的,現在有了Shiros了,我們就可以統一的進行設定許可權問題,Shrios的實現也是很簡單的,下面讓我們來看看具體實現步驟

web.xml配置

  • 因為我們是與spring進行整合的,而spring的基本就是web專案的xml檔案。所以我們在web.xml中配置shiros的過濾攔截。正常情況下,我們需要將shiro的filter配置在所有的filter前面,當然和encodingFilter這個filter是不區分前後的。因為兩者互相不影響的。
<filter>
        <filter-name>shiroFilter</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
        <init-param>
            <!-- 該值預設為false,表示生命週期由SpringApplicationContext管理,設定為true則表示由servlet container管理 -->
<param-name>targetFilterLifecycle</param-name> <param-value>true</param-value> </init-param> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern
>
</filter-mapping>
  • 好了,到這裡shiro就整合到spring專案裡面去了。What?對的,你妹看錯,就這麼簡單,shiro就這一步就整合到專案裡了。整合式集成了,但是想要完整的實現效果當然我們還是需要繼續的往下配置的。在這裡請記住我這裡的shiroq過濾器的名字叫shiroFilter(後面有用的)。下面我們的shiro需要到spring的配置檔案application.xml檔案裡去配置,在我的專案的我的spring配置檔案是spring-service.xml。而在spring-service.xml中又引入了spring-shiro.xml,也就是說最後shiro的配置是配置在spring-shiro.xml檔案中。
    最終原始碼在最後下載

spring-shiro.xml

  • 這裡我們將來看看spring-shiro.xml的配置,這裡我採取倒敘的方式講解,我覺的倒敘更加的有助於我們理解程式碼。首先我們還記得在web.xml中配置的那個filter吧,名字shiroFilter,對spring-shiro.xml配置檔案就是通過這個filter展開的。首先我們在web.xml配置的過濾器實際上是配置ShiroFilterFactoryBean,所以在這裡需要將ShiroFilterFactoryBean定義為shiroFilter
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
        <!-- Shiro的核心安全介面,這個屬性是必須的 -->  
        <property name="securityManager" ref="securityManager"/>  
        <!-- 要求登入時的連結(可根據專案的URL進行替換),非必須的屬性,預設會自動尋找Web工程根目錄下的"/login.html"頁面 -->  
        <property name="loginUrl" value="/login.html"/>  
        <!-- 登入成功後要跳轉的連線 -->  
        <property name="successUrl" value="/index.html"/>
        <!-- 使用者訪問未對其授權的資源時,所顯示的連線 -->  
        <!-- 若想更明顯的測試此屬性可以修改它的值,如unauthor.jsp,然後用[玄玉]登入後訪問/admin/listUser.jsp就看見瀏覽器會顯示unauthor.jsp -->  
        <property name="unauthorizedUrl" value="/login.html"
        />  
        <!-- Shiro連線約束配置,即過濾鏈的定義 -->  
        <!-- 此處可配合我的這篇文章來理解各個過濾連的作用http://blog.csdn.net/jadyer/article/details/12172839 -->  
        <!-- 下面value值的第一個'/'代表的路徑是相對於HttpServletRequest.getContextPath()的值來的 -->  
        <!-- anon:它對應的過濾器裡面是空的,什麼都沒做,這裡.do和.jsp後面的*表示引數,比方說login.jsp?main這種 -->  
        <!-- authc:該過濾器下的頁面必須驗證後才能訪問,它是Shiro內建的一個攔截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter -->  
        <property name="filterChainDefinitions">  
            <value>
                /statics/**=anon
                /login.html=anon
                /sys/schedule.html=perms[sys:schedule:save]
                /sys/login=anon
                /captcha.jpg=anon
                /**=authc
            </value>
        </property>
    </bean>
  • 具體的上面的程式碼註釋已經解釋的很清楚了,在這裡主要講解下filterChainDefinitions裡面的設定屬性。裡面的value就是我們控制的頁面許可權設定。filterChainDefinitions的原則是按順序查詢一旦查詢到符合的頁面要求就不在繼續查找了。所以我們需要將有萬用字元的頁面設定在最後。上面配置中有/sys/schedule.html=perms[sys:schedule:save]
    意思就是說訪問schedule.html這個頁面前提是你得有sys:schedule:save這個許可權。至於這個許可權在哪裡配置。在這裡先透露一下。在Realm中獲取

這裡寫圖片描述

  • 在上面的配置我們securityManager屬性是shiro 安全核心配置介面,這裡需要我們自己填寫,這裡的配置就是需要我們實現我們的認證,因為不同的專案我們認證許可權肯定是不一樣的。所以這也是shiro給我們唯一為數不多的程式碼編寫的介面,我們只需要在這介面提供我們自己的認證和角色許可權分配就行了。
<!-- Shiro預設會使用Servlet容器的Session,可通過sessionMode屬性來指定使用Shiro原生Session -->  
    <!-- 即<property name="sessionMode" value="native"/>,詳細說明見官方文件 -->  
    <!-- 這裡主要是設定自定義的單Realm應用,若有多個Realm,可使用'realms'屬性代替 -->  
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">  
        <property name="realm" ref="userRealm"/>
    </bean>
  • 那麼這裡有出現了一個realm,這個realm就是我們實現許可權和認證的地方。我們只需要通過spring將我們的實現類指定為realm即可
<bean id="userRealm" class="io.renren.shiro.UserRealm"/>
  • 在講UserRealm之前我們先來看看shir預設的realm邏輯是咋樣的

這裡寫圖片描述

  • 通常我們只需要繼承AuthorizingRealm(授權),因為AuthorizingRealm裡面繼承了AuthenticatingRealm(認證),所以我們只需要繼承AuthorizingRealm(授權),我們就可以重寫授權和認證兩個方法了,這兩個方法裡面就實現許可權管理操作。

這裡寫圖片描述

  • 首先來看看在認證登入中我們有哪些值得注意的地方

  • doGetAuthenticationInfo中實現登入認證出現的幾種異常

    • UnknownAccountException:獲取的user為空
    • LockedAccountException :此使用者被鎖住了
    • IncorrectCredentialsException : 密碼不正確(建議提示為 使用者名稱或密碼錯誤。安全考慮)
    • ExcessiveAttemptsException : 密碼錯誤次數太多(現在很多網站上都有相關的操作)
    • 最後通過使用者名稱+明文密碼+Reaml中的getName進行使用者資訊組裝
  • 登入認證就這幾點注意,其次就是許可權分配了,doGetAuthorizationInfo(授權),在doGetAuthorizationInfo裡我們通過PrincipalCollection這個身份集合,當我們只配置了一個Reaml的時候我們可以通過PrincipalCollection中的getPrimaryPrincipal方法獲得剛剛傳入的Reaml(使用者名稱)就行了,但是當我們配置了多個Reaml的時候可以通過PrincipalCollection中的getRealmNames獲取所有的Reaml的使用者名稱就行了。

  • 然後通過使用者名稱去資料庫獲取許可權選單。最後返回一個帶有角色和許可權的 SimpleAuthorization的資訊,意思就是一下角色具有哪些許可權。如果就一個角色的時候也可以不指定角色,分別通過setStringPermissions(指定許可權)+setRoles(指定角色)

  • 到這裡shiro的配置就完成了。

  • 另外還有一點shiro的配置是處理shiro的生命週期和shiro的註解的啟用的,這裡就不解釋了,直接上程式碼

<!-- Shiro生命週期處理器 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    <!-- AOP式方法級許可權檢查  -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
        <property name="proxyTargetClass" value="true" />
    </bean>
    <!-- 開啟shiro註解 -->
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>

spring-shiro.xml原始碼

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
    xmlns:aop="http://www.springframework.org/schema/aop" xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd        
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context-4.2.xsd
        http://www.springframework.org/schema/tx 
        http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
        http://www.springframework.org/schema/aop 
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
        http://www.springframework.org/schema/mvc 
        http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd">

    <!-- 繼承自AuthorizingRealm的自定義Realm,即指定Shiro驗證使用者登入的類為自定義的UserRealm.java -->  
    <bean id="userRealm" class="io.renren.shiro.UserRealm"/>

    <!-- Shiro預設會使用Servlet容器的Session,可通過sessionMode屬性來指定使用Shiro原生Session -->  
    <!-- 即<property name="sessionMode" value="native"/>,詳細說明見官方文件 -->  
    <!-- 這裡主要是設定自定義的單Realm應用,若有多個Realm,可使用'realms'屬性代替 -->  
    <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">  
        <property name="realm" ref="userRealm"/>
    </bean>

    <!-- Shiro主過濾器本身功能十分強大,其強大之處就在於它支援任何基於URL路徑表示式的、自定義的過濾器的執行 -->  
    <!-- Web應用中,Shiro可控制的Web請求必須經過Shiro主過濾器的攔截,Shiro對基於Spring的Web應用提供了完美的支援 -->  
    <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
        <!-- Shiro的核心安全介面,這個屬性是必須的 -->  
        <property name="securityManager" ref="securityManager"/>  
        <!-- 要求登入時的連結(可根據專案的URL進行替換),非必須的屬性,預設會自動尋找Web工程根目錄下的"/login.html"頁面 -->  
        <property name="loginUrl" value="/login.html"/>  
        <!-- 登入成功後要跳轉的連線 -->  
        <property name="successUrl" value="/index.html"/>
        <!-- 使用者訪問未對其授權的資源時,所顯示的連線 -->  
        <!-- 若想更明顯的測試此屬性可以修改它的值,如unauthor.jsp,然後用[玄玉]登入後訪問/admin/listUser.jsp就看見瀏覽器會顯示unauthor.jsp -->  
        <property name="unauthorizedUrl" value="/login.html"
        />  
        <!-- Shiro連線約束配置,即過濾鏈的定義 -->  
        <!-- 此處可配合我的這篇文章來理解各個過濾連的作用http://blog.csdn.net/jadyer/article/details/12172839 -->  
        <!-- 下面value值的第一個'/'代表的路徑是相對於HttpServletRequest.getContextPath()的值來的 -->  
        <!-- anon:它對應的過濾器裡面是空的,什麼都沒做,這裡.do和.jsp後面的*表示引數,比方說login.jsp?main這種 -->  
        <!-- authc:該過濾器下的頁面必須驗證後才能訪問,它是Shiro內建的一個攔截器org.apache.shiro.web.filter.authc.FormAuthenticationFilter -->  
        <property name="filterChainDefinitions">  
            <value>
                /statics/**=anon
                /login.html=anon
                /sys/schedule.html=perms[sys:schedule:save]
                /sys/login=anon
                /captcha.jpg=anon
                /**=authc
            </value>
        </property>
    </bean>
    <!-- Shiro生命週期處理器 -->
    <bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>

    <!-- AOP式方法級許可權檢查  -->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator" depends-on="lifecycleBeanPostProcessor">
        <property name="proxyTargetClass" value="true" />
    </bean>
    <!-- 開啟shiro註解 -->
    <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
        <property name="securityManager" ref="securityManager"/>
    </bean>
</beans>

Shiro的其他許可權過濾器及其用法

  • anon :org.apache.shiro.web.filter.authc.AnonymousFilter

/statics/**=anon :以statics開頭的請求可以隨便訪問,沒有許可權

  • authc:org.apache.shiro.web.filter.authc.FormAuthenticationFilter

/**=authc :表示所有的請求都需要進行驗證許可權且許可權通過才能放行


  • authcBasic:org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter

/admins/user/**=authcBasic :表示沒有通過httpbasic認證的


  • perms:org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter

/admins/user/*=perms[user:add:] :上面已經解釋過了,表示訪問./admins/user/..
的請求必須是由use:add:*許可權的才可以訪問,否則重定向登入頁面(這裡的登入頁面預設是web下的login.html,正常我們通過設定shiro中的filterChainDefinitions屬性設定頁面)。

  • port : org.apache.shiro.web.filter.authz.PortFilter

/admins/user/**=port[8081] :
當訪問的請求埠不是8001時,則shiro會重定向到schemal://serverName:8081?queryString請求。這個請求中schemal是http或者https,serverName是我們原請求中的域名,8081就是我們port裡設定埠號,queryString是我們原請求中攜帶的引數。

  • rest :org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter

/admins/user/**=rest[user] :
rest表示請求方法。相當於perms[user:method],這裡method值得是post,get , delete.

  • roles :org.apache.shiro.web.filter.authz.RolesAuthorizationFilter

/admins/user/**=roles[admin] :
這個和perms使用時一樣的,只不過在後臺我們是通過setRoles方法給使用者設定角色的。

  • ssl : org.apache.shiro.web.filter.authz.SslFilter

/admins/user/**=ssl : 表示該請求是安全請求,協議是https

  • user : org.apache.shiro.web.filter.authc.UserFilter

/admins/user/**=user 表示必須存在使用者,在登入操作是不進行檢查的,因為登入的時候根本就不存在使用者。

  • logout : org.apache.shiro.web.filter.authc.LogoutFilter

/admins/user/**=logout : 表示該請求是退出操作


注意!上面中roles,perms,rest這三個裡面是可以帶引數的,如果有多個引數引數之間必須用英文裝填下的逗號分隔。在頁面中判斷是所有引數都滿足才算是滿足的。

以上是自己根據別的文章加上自己認識總結,參考一下文章