shiro權限管理
Shiro 是一個強大而靈活的開源安全框架,能夠非常清晰的處理認證、授權、管理會話以及密碼加密。
特點:
1:易於理解的 Java Security API
2:簡單的身份認證(登錄),支持多種數據源(LDAP,JDBC,Kerberos,ActiveDirectory 等)
3:對角色的簡單的籤權(訪問控制),支持細粒度的籤權
4:支持一級緩存,以提升應用程序的性能
5:內置的基於 POJO 企業會話管理,適用於 Web 以及非 Web 的環境
6:異構客戶端會話訪問
7:非常簡單的加密 API
8:不跟任何的框架或者容器捆綁,可以獨立運行
Shiro 主要有四個組件:
SecurityManager:
典型的 Facade,Shiro 通過它對外提供安全管理的各種服務
Authenticator:
1:對“Who are you ?”進行覈實。通常涉及用戶名和密碼
2:這個組件負責收集 principals 和 credentials,並將它們提交給應用系統,如果提交的credentials 跟應用系統中提供的 credentials 吻合,就能夠繼續訪問。否則需要重新提交 principals 和 credentials,或者直接終止訪問。
Authorizer:
1:身份份驗證通過後,由這個組件對登錄人員進行訪問控制的篩查,比如“who can do what”, 或者“who can do which actions”。
2:Shiro 採用“基於 Realm”的方法,即用戶(又稱 Subject)、用戶組、角色和 permission 的聚合體。
Session Manager:
這個組件保證了異構客戶端的訪問,配置簡單。它是基於 POJO/J2SE 的,不跟任何的客戶端或者協議綁定
Shiro 的認證和籤權可以通過 JDBC、LDAP 或者 Active Directory 來訪問數據庫、目錄服務器或者 Active Directory 中的人員以及認證 / 籤權信息。SessionManager 通過會話 DAO 可以將會話保存在 cache 中,或者固化到數據庫或文件系統中
shiro可以做什麼?
1:支持認證跨一個或多個數據源(LDAP,JDBC,kerberos身份等)
2:執行授權,基於角色的細粒度的權限控制
3:增強的緩存的支持
4:支持web或者非web環境,可以在任何單點登錄(SSO)---ticket或集羣分佈式會話中使用
5:主要功能是:認證,授權,會話管理和加密
Shiro支持三種方式實現授權過程:
1:編碼實現
2:註解實現
3:jsp tablib標籤
Shiro提供了一套JSP標籤庫來實現頁面級的授權控制
在使用Shiro標籤庫前,首先需要在JSP引入shiro標籤
註解:
Shiro註解支持AspectJ、Spring、Google-Guice等
@RequiresAuthentication:
可以用於用戶類/屬性/方法
@RequiresGuest
表明該用戶需爲”guest”用
@RequiresPermissions("account:create")
當前用戶需擁有制定權限戶 於表明當前用戶需是經過認證的用戶
@RequiresRoles
當前用戶需擁有制定角色
@RequiresUser
當前用戶需爲已認證用戶或已記住用戶
Shiro的具體功能點如下:
1. 身份認證/登錄,驗證用戶是不是擁有相應的身份
2. 授權,即權限驗證,驗證某個已認證的用戶是否擁有某個權限;即判斷用戶是否能做事情,常見的如:驗證某個用戶是否擁有某個角色。或者細粒度的驗證某個用戶對某個資源是否具有某個權限
3. 會話管理,即用戶登錄後就是一次會話,在沒有退出之前,它的所有信息都在會話中;會話可以是普通JavaSE環境的,也可以是如Web環境的
4. 加密,保護數據的安全性,如密碼加密存儲到數據庫,而不是明文存儲
5. Web支持,可以非常容易的集成到Web環境,Caching:緩存,比如用戶登錄後,其用戶信息、擁有的角色/權限不必每次去查,這樣可以提高效率
6. shiro支持多線程應用的併發驗證,即如在一個線程中開啓另一個線程,能把權限自動傳播過去
7. 提供測試支持
8. 允許一個用戶假裝爲另一個用戶(如果他們允許)的身份進行訪問
9. 記住我,這個是非常常見的功能,即一次登錄後,下次再來的話不用登錄了
shiro入門示例
步驟:
1:在啓動容器中,增加shiro的filter過濾器
2:增加shiro的配置文件信息,shiro.xml
3:在shiro.xml配置文件中,增加自己的自定義relam(認證(查詢用戶名和密碼信息)、授權(角色信息),自己寫一個查詢數據庫的用戶名、密碼、角色等用戶信息)
4:在控制層controller,增加登錄(login())和退出方法(logout())
5:提示對應的登錄返回信息即可
代碼:
web.xml中增加配置:
<!-- shiro過濾器 -->
<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>
<filter-mapping>
<filter-name>shiroFilter</filter-name>
<url-pattern>*.jhtml</url-pattern>
<url-pattern>*.json</url-pattern>
</filter-mapping>
shiro配置文件: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"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
default-lazy-init="true">
<description>Shiro Configuration</description>
<!-- Shiro's main business-tier object for web-enabled applications -->
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
<property name="realm" ref="myShiroRealm" /> <!--自定義過濾(攔截) -->
<property name="cacheManager" ref="cacheManager" />
</bean>
<!-- 項目自定義的Realm -->
<bean id="myShiroRealm" class="com.xdl.shiro.realm.MyShiroRealm">
<property name="cacheManager" ref="cacheManager" />
</bean>
<!-- Shiro Filter -->
<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/login.jhtml" />
<property name="successUrl" value="/loginsuccess.jhtml" />
<property name="unauthorizedUrl" value="/error.jhtml" />
<property name="filterChainDefinitions">
<!--是有先後順序的 -->
<value>
/index.jhtml = authc
/login.jhtml = anon
/checkLogin.json = anon
/loginsuccess.jhtml = anon
/logout.json = anon
/** = authc
</value>
</property>
</bean>
<!-- 用戶授權信息Cache -->
<bean id="cacheManager" class="org.apache.shiro.cache.MemoryConstrainedCacheManager" />
<!-- 保證實現了Shiro內部lifecycle函數的bean執行 -->
<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>
<bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor">
<property name="securityManager" ref="securityManager" />
</bean>
</beans>
shiro.xml配置文件說明:
”shiroFilter” 這個bean裏面的各個屬性property的含義:
(1)securityManager:這個屬性是必須的,沒什麼好說的,就這樣配置就好。
(2)loginUrl:沒有登錄的用戶請求需要登錄的頁面時自動跳轉到登錄頁面,可配置也可不配置。
(3)successUrl:登錄成功默認跳轉頁面,不配置則跳轉至”/”,一般可以不配置,直接通過代碼進行處理。
(4)unauthorizedUrl:沒有權限默認跳轉的頁面。
(5)filterChainDefinitions,對於過濾器就有必要詳細說明一下:
1)Shiro驗證URL時,URL匹配成功便不再繼續匹配查找(所以要注意配置文件中的URL順序,尤其在使用通配符時),故filterChainDefinitions的配置順序爲自上而下,以最上面的爲準
2)當運行一個Web應用程序時,Shiro將會創建一些有用的默認Filter實例,並自動地在[main]項中將它們置爲可用自動地可用的默認的Filter實例是被DefaultFilter枚舉類定義的,枚舉的名稱字段就是可供配置的名稱
3)通常可將這些過濾器分爲兩組:
anon,authc,authcBasic,user是第一組認證過濾器
perms,port,rest,roles,ssl是第二組授權過濾器
注意user和authc不同:當應用開啓了rememberMe時,用戶下次訪問時可以是一個user,但絕不會是authc,因爲authc是需要重新認證的 user表示用戶不一定已通過認證,只要曾被Shiro記住過登錄狀態的用戶就可以正常發起請求,比如rememberMe
說白了,以前的一個用戶登錄時開啓了rememberMe,然後他關閉瀏覽器,下次再訪問時他就是一個user,而不會authc
4)舉幾個例子
/admin=authc,roles[admin] 表示用戶必需已通過認證,並擁有admin角色纔可以正常發起’/admin’請求
/edit=authc,perms[admin:edit] 表示用戶必需已通過認證,並擁有admin:edit權限纔可以正常發起’/edit’請求
/home=user 表示用戶不一定需要已經通過認證,只需要曾經被Shiro記住過登錄狀態就可以正常發起’/home’請求
5)各默認過濾器常用如下(注意URL Pattern裏用到的是兩顆星,這樣才能實現任意層次的全匹配)
/admins/**=anon 無參,表示可匿名使用,可以理解爲匿名用戶或遊客
/admins/user/**=authc 無參,表示需認證才能使用
/admins/user/**=authcBasic 無參,表示httpBasic認證
/admins/user/**=user 無參,表示必須存在用戶,當登入操作時不做檢查
/admins/user/**=ssl 無參,表示安全的URL請求,協議爲https
/admins/user/*=perms[user:add:] 參數可寫多個,多參時必須加上引號,且參數之間用逗號分割,如/admins/user/*=perms[“user:add:,user:modify:*”] 當有多個參數時必須每個參數都通過纔算通過,相當於isPermitedAll()方法
/admins/user/**=port[8081]當請求的URL端口不是8081時,跳轉到schemal://serverName:8081?queryString 其中schmal是協議http或https等,serverName是你訪問的Host,8081是Port端口,queryString是你訪問的URL裏的?後面的參數
/admins/user/**=rest[user]根據請求的方法,相當於/admins/user/**=perms[user:method],其中method爲post,get,delete等
/admins/user/**=roles[admin]參數可寫多個,多個時必須加上引號,且參數之間用逗號分割,如/admins/user/**=roles[“admin,guest”]當有多個參數時必須每個參數都通過纔算通過,相當於hasAllRoles()方法