shiro用的好的話抗住千萬流量沒問題!自定義過濾器鑑權|Java 開發實戰

這是我參與更文挑戰的第4天,活動詳情查看: 更文挑戰html

本文正在參加「Java主題月 - Java 開發實戰」,詳情查看 活動連接java

Shiros是咱們開發中經常使用的用來實現權限控制的一種工具包ios

Shiros是咱們開發中經常使用的用來實現權限控制的一種工具包,它主要有認證、受權、加密、會話管理、與Web集成、緩存等功能。我是從事javaweb工做的,我就常常遇到須要實現權限控制的項目,以前咱們都是靠查詢數據獲取列表拼接展現的,還有的是及時的判斷權限的問題的,如今有了Shiros了,咱們就能夠統一的進行設置權限問題,Shrios的實現也是很簡單的,下面讓咱們來看看具體實現步驟web

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

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(受權),咱們就能夠重寫受權和認證兩個方法了,這兩個方法裏面就實現權限管理操做。

這裏寫圖片描述

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

  • doGetAuthenticationInfo中實現登陸認證出現的幾種異常瀏覽器

    • UnknownAccountException:獲取的user爲空
    • LockedAccountException :此用戶被鎖住了
    • IncorrectCredentialsException : 密碼不正確(建議提示爲 用戶名或密碼錯誤。安全考慮)
    • ExcessiveAttemptsException : 密碼錯誤次數太多(如今不少網站上都有相關的操做)
    • 最後經過用戶名+明文密碼+Reaml中的getName進行用戶信息組裝
  • 登陸認證就這幾點注意,其次就是權限分配了,doGetAuthorizationInfo(受權),在doGetAuthorizationInfo裏咱們經過PrincipalCollection這個身份集合,當咱們只配置了一個Reaml的時候咱們能夠經過PrincipalCollection中的getPrimaryPrincipal方法得到剛剛傳入的Reaml(用戶名)就好了,可是當咱們配置了多個Reaml的時候能夠經過PrincipalCollection中的getRealmNames獲取全部的Reaml的用戶名就好了。spring-mvc

  • 而後經過用戶名去數據庫獲取權限菜單。最後返回一個帶有角色和權限的 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這三個裏面是能夠帶參數的,若是有多個參數參數之間必須用英文裝填下的逗號分隔。在頁面中判斷是全部參數都知足纔算是知足的。
相關文章
相關標籤/搜索