shiro基礎知識

什麼是權限管理?

權限管理是系統的安全範疇,要求必須是合法的用戶纔可以訪問系統(用戶認證),且必須具有該 資源的訪問權限纔可以訪問該 資源(授權)。

認證:對用戶合法身份的校驗,要求必須是合法的用戶纔可以訪問系統。

授權:訪問控制,必須具有該 資源的訪問權限纔可以訪問該 資源。

 

權限模型:標準權限數據模型包括 :用戶、角色、權限(包括資源和權限)、用戶角色關係、角色權限關係。

權限分配:通過UI界面方便給用戶分配權限,對上邊權限模型進行增、刪、改、查操作。

權限控制:

基於角色的權限控制:根據角色判斷是否有操作權限,因爲角色的變化 性較高,如果角色修改需要修改控制代碼,系統可擴展性不強。

基於資源的權限控制:根據資源權限判斷是否有操作權限,因爲資源較爲固定,如果角色修改或角色中權限修改不需要修改控制代碼,使用此方法系統可維護性很強。建議使用。

 

權限管理的解決方案:

 對於粗顆粒權限管理,建議在系統架構層面去解決,寫系統架構級別統一代碼(基礎代碼)。

粗顆粒權限:比如對系統的url、菜單、jsp頁面、頁面上按鈕、類方法進行權限管理,即對資源類型進行權限管理。

 

對於細顆粒權限管理

粗顆粒權限:比如用戶id001的用戶信息(資源實例)、類型爲t01的商品信息(資源實例),對資源實例進行權限管理,理解對數據級別的權限管理。

細顆粒權限管理是系統的業務邏輯,業務邏輯代碼不方便抽取統一代碼,建議在系統業務層進行處理。

 

基於url的權限管理(掌握):

企業開發常用的方法,使用web應用中filter來實現,用戶請求url,通過filter攔截,判斷用戶身份是否合法(用戶認證),判斷請求的地址是否是用戶權限範圍內的url(授權)

 

shiro

shiro是一個權限管理框架,是apache下的開源項目。相比spring security框架更簡單靈活,spring securityspring依賴較強。shiro可以實現web系統、c/s、分佈式等系統 權限管理。

 

shiro認證流程:重要

1subject(主體)請求認證,調用subject.login(token)

2SecurityManager (安全管理器)執行認證

3SecurityManager通過ModularRealmAuthenticator進行認證。

4ModularRealmAuthenticatortoken傳給realmrealm根據token中用戶信息從數據庫查詢用戶信息(包括身份和憑證)

5realm如果查詢不到用戶給ModularRealmAuthenticator返回nullModularRealmAuthenticator拋出異常(用戶不存在)

6realm如果查詢到用戶給ModularRealmAuthenticator返回AuthenticationInfo(認證信息)

7ModularRealmAuthenticator拿着AuthenticationInfo(認證信息)去進行憑證(密碼 )比對。如果一致則認證通過,如果不致拋出異常(憑證錯誤)。

subject:主體

Authenticator:認證器( shiro提供)

realm一般需要自定義:相當於數據源,認證器需要realm從數據源查詢用戶身份信息及權限信息。

授權流程

1、對subject進行授權,調用方法isPermitted"permission"

2SecurityManager執行授權,通過ModularRealmAuthorizer執行授權

3ModularRealmAuthorizer執行realm(自定義的CustomRealm)從數據庫查詢權限數據

   調用realm的授權方法:doGetAuthorizationInfo

4realm從數據庫查詢權限數據,返回ModularRealmAuthorizer

5ModularRealmAuthorizer調用PermissionResolver進行權限串比對

6、如果比對後,isPermitted"permission"realm查詢到權限數據中,說明用戶訪問permission串有權限,否則 沒有權限,拋出異常。

使用maven整合shiro和ssm 

web.xml中的配置

額外添加

  <!-- shiro過濾器定義 -->
<filter>  
   <filter-name>shiroFilter</filter-name>  
   <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
    <init-param>  
    <!-- 該值缺省爲false,表示生命週期由SpringApplicationContext管理,設置爲true則表示由ServletContainer管理 -->  
    <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>

可以查看官方文檔

pom.xml中需要添加的配置

<!--使用shiro需要的包  -->
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-core -->
<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-core</artifactId>
   <version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-web -->
<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-web</artifactId>
   <version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-spring -->
<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-spring</artifactId>
   <version>1.4.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.shiro/shiro-ehcache -->
<dependency>
   <groupId>org.apache.shiro</groupId>
   <artifactId>shiro-ehcache</artifactId>
   <version>1.2.3</version>
</dependency>

自定義spring-shiro.xml即網上說的application-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.xsd
       http://www.springframework.org/schema/context 
                http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/tx 
       http://www.springframework.org/schema/tx/spring-tx.xsd
       http://www.springframework.org/schema/aop 
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/mvc
                http://www.springframework.org/schema/mvc/spring-mvc.xsd"> 
               
   
<!-- 安全管理器 -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">  
   <!--注入自定義的realm  -->
   <property name="realm" ref="myRealm"/>  
 <!-- 注入session管理器 -->
 <property name="sessionManager" ref="sessionManager" />
 <!-- 注入緩存管理器 -->
 <property name="cacheManager" ref="cacheManager"/>
 <!-- 記住我 -->
 <property name="rememberMeManager" ref="rememberMeManager"/>
</bean> 
<!-- 自定義Realm -->
<bean id="myRealm" class="com.csl.realm.MyRealm">
   <!--將憑證匹配器設置到realm中,realm按照憑證匹配器的要求進行散列 -->
   <property name="credentialsMatcher" ref="credentialsMatcher"/>
</bean> 
 <!--添加憑證匹配器  -->
   <bean id="credentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
          <property name="hashAlgorithmName" value="md5"/>
          <property name="hashIterations" value="2"/>
    </bean>
<!-- ================================  --> 
<!-- rememberMeManager管理器,寫cookie,取出cookie生成用戶信息 -->
<bean id="rememberMeManager" class="org.apache.shiro.web.mgt.CookieRememberMeManager">
<property name="cookie" ref="rememberMeCookie" />
</bean>
<!-- 記住我cookie -->
<bean id="rememberMeCookie" class="org.apache.shiro.web.servlet.SimpleCookie">
<!-- rememberMe是cookie的名字 -->
<constructor-arg value="rememberMe" />
<!-- 記住我cookie生效時間30天 -->
<property name="maxAge" value="2592000" />
</bean>
    <!-- ================================  -->
<!--緩存管理器  -->
    <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">  
        <property name="cacheManagerConfigFile" value="classpath:resources/shiro-ehcache.xml"/>  
    </bean>   
    <!-- ================================  -->
<!-- 會話管理器 -->
    <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager">
        <!-- session的失效時長,單位毫秒 -->
        <property name="globalSessionTimeout" value="600000"/>
        <!-- 刪除失效的session -->
        <property name="deleteInvalidSessions" value="true"/>
    </bean>


<!-- Shiro過濾器 -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">  
   <!-- Shiro的核心安全接口,這個屬性是必須的 -->  
   <property name="securityManager" ref="securityManager"/>
   <!-- 身份認證失敗,則跳轉到登錄頁面的配置 -->  
   <property name="loginUrl" value="/login.jsp"/>
   <!-- 權限認證失敗,則跳轉到指定頁面 -->  
   <property name="unauthorizedUrl" value="/unauthor.jsp"/>  
   <!-- 自定義filter配置 比如驗證碼,要在認證之前-->
   <!-- 
<property name="filters">
<map>
將自定義 的FormAuthenticationFilter注入shiroFilter中
<entry key="authc" value-ref="formAuthenticationFilter"/>
</map>
</property>
-->
<!-- Shiro連接約束配置,即過濾鏈的定義 -->  
   <property name="filterChainDefinitions">  
       <value>  
            /index.jsp=anon
            /login.jsp=anon
/admin*=authc
/role*=anon
                 /login.do= roles[admin],perms["user:view"]
       </value>  
   </property>
</bean>  

<!-- 保證實現了Shiro內部lifecycle函數的bean執行 -->  
<bean id="lifecycleBeanPostProcessor" class="org.apache.shiro.spring.LifecycleBeanPostProcessor"/>  

<!-- 開啓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>  
    <!--開啓aop對類代理  -->
    <aop:config proxy-target-class="true"></aop:config>    
</beans>

緩存管理器還得需要導入shiro-ehcache.xml

  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <ehcache name="es">  
  3.     <diskStore path="java.io.tmpdir"/>  
  4.          <!--  
  5.        name:緩存名稱。  
  6.        maxElementsInMemory:緩存最大數目  
  7.        maxElementsOnDisk:硬盤最大緩存個數。   
  8.        eternal:對象是否永久有效,一但設置了,timeout將不起作用。   
  9.        overflowToDisk:是否保存到磁盤,當系統當機時  
  10.        timeToIdleSeconds:設置對象在失效前的允許閒置時間(單位:秒)。僅當eternal=false對象不是永久有效時使用,可選屬性,默認值是0,也就是可閒置時間無窮大。  
  11.        timeToLiveSeconds:設置對象在失效前允許存活時間(單位:秒)。最大時間介於創建時間和失效時間之間。僅當eternal=false對象不是永久有效時使用,默認是0.,也就是對象存活時間無窮大。  
  12.        diskPersistent:是否緩存虛擬機重啓期數據 Whether the disk store persists between restarts of the Virtual Machine. The default value is false.   
  13.        diskSpoolBufferSizeMB:這個參數設置DiskStore(磁盤緩存)的緩存區大小。默認是30MB。每個Cache都應該有自己的一個緩衝區。   
  14.        diskExpiryThreadIntervalSeconds:磁盤失效線程運行時間間隔,默認是120秒。  
  15.        memoryStoreEvictionPolicy:當達到maxElementsInMemory限制時,Ehcache將會根據指定的策略去清理內存。默認策略是LRU(最近最少使用)。你可以設置爲FIFO(先進先出)或是LFU(較少使用)。   
  16.        clearOnFlush:內存數量最大時是否清除。  
  17.        memoryStoreEvictionPolicy:  
  18.             Ehcache的三種清空策略;  
  19.             FIFO,first in first out,這個是大家最熟的,先進先出。  
  20.             LFU, Less Frequently Used,就是上面例子中使用的策略,直白一點就是講一直以來最少被使用的。如上面所講,緩存的元素有一個hit屬性,hit值最小的將會被清出緩存。  
  21.             LRU,Least Recently Used,最近最少使用的,緩存的元素有一個時間戳,當緩存容量滿了,而又需要騰出地方來緩存新的元素的時候,那麼現有緩存元素中時間戳離當前時間最遠的元素將被清出緩存。  
  22.     -->  
  23.     <defaultCache  
  24.             maxElementsInMemory="10000"  
  25.             eternal="false"  
  26.             timeToIdleSeconds="120"  
  27.             timeToLiveSeconds="120"  
  28.             overflowToDisk="false"  
  29.             diskPersistent="false"  
  30.             diskExpiryThreadIntervalSeconds="120"  
  31.             />  
  32.     <!-- 登錄記錄緩存鎖定10分鐘 -->  
  33.     <cache name="passwordRetryCache"  
  34.            maxEntriesLocalHeap="2000"  
  35.            eternal="false"  
  36.            timeToIdleSeconds="3600"  
  37.            timeToLiveSeconds="0"  
  38.            overflowToDisk="false"  
  39.            statistics="true">  
  40.     </cache>  
  41. </ehcache>  

     登錄驗證原理

 登陸原理

使用FormAuthenticationFilter過慮器實現 ,原理如下:

 

將用戶沒有認證時,請求loginurl進行認證,用戶身份和用戶密碼提交數據到loginurl

FormAuthenticationFilter攔截住取出request中的username和password(兩個參數名稱是可以配置的)

FormAuthenticationFilter調用realm傳入一個token(username和password)

realm認證時根據username查詢用戶信息(在Activeuser中存儲,包括 userid、usercode、username、menus)。

如果查詢不到,realm返回null,FormAuthenticationFilter向request域中填充一個參數(記錄了異常信息)


由於FormAuthenticationFilter的用戶身份和密碼的input的默認值(username和password),修改頁面的賬號和密碼 的input的名稱爲username和password(可以更改)

 使用PermissionsAuthorizationFilter

spring-shiro.xml中配置url所對應的權限。

 

測試流程:

1、在spring-shiro.xml中配置filter規則

<!--商品查詢需要商品查詢權限  -->

/items/queryItems.action = perms[item:query]

2、用戶在認證通過後,請求/items/queryItems.action

3、被PermissionsAuthorizationFilter攔截,發現需要“item:query”權限

4PermissionsAuthorizationFilter調用realm中的doGetAuthorizationInfo獲取數據庫中正確的權限

5PermissionsAuthorizationFilteritem:query 和從realm中獲取權限進行對比,如果“item:query”在realm返回的權限列表中,授權通過。

==============================================

shiro的過慮器

過濾器簡稱

對應的java類

anon

org.apache.shiro.web.filter.authc.AnonymousFilter

authc

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

authcBasic

org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter

perms

org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter

port

org.apache.shiro.web.filter.authz.PortFilter

rest

org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter

roles

org.apache.shiro.web.filter.authz.RolesAuthorizationFilter

ssl

org.apache.shiro.web.filter.authz.SslFilter

user

org.apache.shiro.web.filter.authc.UserFilter

logout

org.apache.shiro.web.filter.authc.LogoutFilter

 

anon:例子/admins/**=anon 沒有參數,表示可以匿名使用。

authc:例如/admins/user/**=authc表示需要認證(登錄)才能使用,FormAuthenticationFilter是表單認證,沒有參數

perms例子/admins/user/**=perms[user:add:*],參數可以寫多個,多個時必須加上引號,並且參數之間用逗號分割,例如/admins/user/**=perms["user:add:*,user:modify:*"]當有多個參數時必須每個參數都通過才通過,想當於isPermitedAll()方法。

user:例如/admins/user/**=user沒有參數表示必須存在用戶, 身份認證通過或通過記住我認證通過的可以訪問,當登入操作時不做檢查

註解的方式  

 @RequiresPermissions("user:view")


jsp標籤

 

Jsp頁面添加:

<%@ tagliburi="http://shiro.apache.org/tags" prefix="shiro" %>

 

標籤名稱

標籤條件(均是顯示標籤內容)

<shiro:authenticated>

登錄之後

<shiro:notAuthenticated>

不在登錄狀態時

<shiro:guest>

用戶在沒有RememberMe時

<shiro:user>

用戶在RememberMe時

<shiro:hasAnyRoles name="abc,123" >

在有abc或者123角色時

<shiro:hasRole name="abc">

擁有角色abc

<shiro:lacksRole name="abc">

沒有角色abc

<shiro:hasPermission name="abc">

擁有權限資源abc

<shiro:lacksPermission name="abc">

沒有abc權限資源

<shiro:principal>

顯示用戶身份名稱

 <shiro:principal property="username"/>     顯示用戶身份中的屬性值

 

 <shiro:hasPermission name="user:view">
        <input type="button" value="有權限"/>
 </shiro:hasPermission>

授權測試

當調用controller的一個方法,由於該 方法加了@RequiresPermissions("item:query") shiro調用realm獲取數據庫中的權限信息,看"item:query"是否在權限數據中存在,如果不存在就拒絕訪問,如果存在就授權通過。

 

當展示一個jsp頁面時,頁面中如果遇到<shiro:hasPermission name="item:update">shiro調用realm獲取數據庫中的權限信息,看item:update是否在權限數據中存在,如果不存在就拒絕訪問,如果存在就授權通過。

 

問題:只要遇到註解或jsp標籤的授權,都會調用realm方法查詢數據庫,需要使用緩存解決此問題。


shiro緩存

爲了避免頻繁的授權查詢數據庫,使用shiro緩存

緩存流程

shiro中提供了對認證信息和授權信息的緩存。shiro默認是關閉認證信息緩存的,對於授權信息的緩存shiro默認開啓的。主要研究授權信息緩存,因爲授權的數據量大。

 

用戶認證通過。

用戶第一次授權:調用realm查詢數據庫

用戶第二次授權:不調用realm查詢數據庫,直接從緩存中取出授權信息(權限標識符)。

使用maven座標<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-ehcache</artifactId>
    <version>1.2.3</version>
</dependency>

導入jar包 共有兩個 有依賴關係


緩存清空

如果用戶正常退出,緩存自動清空。

如果用戶非正常退出,緩存自動清空。

如果修改了用戶的權限,而用戶不退出系統,修改的權限無法立即生效。

需要手動進行編程實現:

在權限修改後調用realmclearCache方法清除緩存。

service中,權限修改後調用realm的方法。

realm中定義clearCached方法:

//清除緩存

public void clearCached() {

PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();

super.clearCache(principals);

}

在service層首先要注入realm 調用realm中的方法清除緩存

實現記住我功能

 首要將身份實現serializable接口

 配置rememberMeManager

 登錄頁面的 input標籤的(type="chheckbox")name屬性也要爲rememberMe








































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