簡單的介紹,簡單的配置,簡單的擴展
一、shiro簡介
Apache Shiro是一個強大而靈活的開源安全框架,它能夠干凈利落地處理身份認證,授權,企業會話管理和加密。
以下是你可以用 Apache Shiro所做的事情:
1. 驗證用戶
2. 對用戶執行訪問控制,如:
判斷用戶是否擁有角色admin。
判斷用戶是否擁有訪問的權限
3. 在任何環境下使用 Session API。例如CS程序。
4. 可以使用多個用戶數據源。例如一個是oracle用戶庫,另外一個是mysql用戶庫。
5. 單點登錄(SSO)功能。
6. “Remember Me”服務 ,類似購物車的功能,shiro官方建議開啟。
Shiro的4大部分——身份驗證,授權,會話管理和加密
Authentication:身份驗證,簡稱“登錄”
Authorization:授權,給用戶分配角色或者權限資源
Session Management:用戶session管理器,可以讓CS程序也 使用session來控制權限
• Cryptography:把JDK中復雜的密碼加密方式進行封裝。
除了以上功能,shiro還提供很多擴展
• Web Support:主要針對web應用提供一些常 用功能。
• Caching:緩存可以使應用程序運行更有效率。
•Concurrency:多線程相關功能。
• Testing:幫助我們進行測試相關功能
• "Run As":一個允許用戶假設為另一個用戶 身份(如果允許)的功能,有時候在管理腳本 很有用。
• “Remember Me”:記住用戶身份,提供類似購物車功能。

Subject:
Subject 是與程序進行交互的對象,可以是人也可以是服務或者其他,通常就理解為用戶。
所有Subject 實例都必須綁定到一個SecurityManager上。我們與一個 Subject 交互, 運行時shiro會自動轉化為與 SecurityManager交互的特定 subject的交互。
SecurityManager:
SecurityManager 是 Shiro的核心,初始化時協調各個模塊運行。然而,一 旦 SecurityManager協調完畢,SecurityManager 會被單獨留下,且我 們只需要去操作Subject即可,無需操SecurityManager 。 但是我們 得知道,當我們正與一個 Subject 進行交互時,實質上是 SecurityManager在處理 Subject 安全操作。
Realms:
Realms在 Shiro中作為應用程序和安全數據之間的“橋梁”或“連接器”。 他獲取安全數據來判斷subject是否能夠登錄,subject擁有什么權限。 他有點類似DAO。在配置realms時,需要至少一個realm。而且Shiro提 供了一些常用的 Realms來連接數據源,如LDAP數據源的 JndiLdapRealm,JDBC數據源的JdbcRealm,ini文件數據源的IniRealm, properties文件數據源PropertiesRealm,等等。我們也可以插入自己 的 Realm實現來代表自定義的數據源。 像其他組件一樣,Realms也是 由SecurityManager控制.

小結:
1.Subject(org.apache.shiro.subject.Subject):簡稱用戶
2.SecurityManager(org.apache.shiro.mgt.SecurityManager):
如上所述,SecurityManager是shiro的核心,協調shiro的各個組件
3.Authenticator(org.apache.shiro.authc.Authenticator):登錄控制
注:Authentication Strategy
(org.apache.shiro.authc.pam.AuthenticationStrategy)
如果存在多個realm,則接口AuthenticationStrategy會確定什 么樣算是登錄成功(例如,如果一個Realm成功,而其他的 均失敗,是否登錄成功?)。
4.Authorizer(org.apache.shiro.authz.Authorizer) : 決定subject能擁有什么樣角色或者權限。
5.SessionManager(org.apache.shiro.session.SessionManager) : 創建和管理用戶session。通過設置這個管理器,shiro可以在 任何環境下使用session。
6.CacheManager(org.apahce.shiro.cache.CacheManager) : 緩存管理器,可以減少不必要的后台訪問。提高應用效率,增 加用戶體驗。
7.Cryptography(org.apache.shiro.crypto.*) :Shiro的api大幅度簡化java api中繁瑣的密碼加密。
8.Realms(org.apache.shiro.realm.Realm) :程序與安全數據的橋梁
二,簡單配置
注:這里只介紹spring配置模式。 因為官方例子雖然中有更加簡潔的ini配置形式,但是使用ini配置無法與spring整合。而且兩種配置方法一樣,只是格式不一樣。涉及的jar包
|
Jar
包名稱
|
版本
|
|
核心包
shiro-core
|
1.2.0
|
|
Web
相關包
shiro-web
|
1.2.0
|
|
緩存包
shiro-ehcache
|
1.2.0
|
|
與
spring
整合包
shiro-spring
|
1.2.0
|
|
Ehcache
緩存核心包
ehcache-core
|
2.5.3
|
|
Shiro
自身日志包
slf4j-jdk14
|
1.6.4
|
使用maven時,在pom中添加依賴包
<dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-core</artifactId> <version>1.2.0</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-web</artifactId> <version>1.2.0</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-ehcache</artifactId> <version>1.2.0</version> </dependency> <dependency> <groupId>org.apache.shiro</groupId> <artifactId>shiro-spring</artifactId> <version>1.2.0</version> </dependency> <dependency> <groupId>net.sf.ehcache</groupId> <artifactId>ehcache-core</artifactId> <version>2.5.3</version> </dependency> <dependency> <groupId>org.slf4j</groupId> <artifactId>slf4j-jdk14</artifactId> <version>1.6.4</version> </dependency>
Spring整合配置
<!-- Shiro filter--> <filter> <filter-name>shiroFilter</filter-name> <filter-class> org.springframework.web.filter.DelegatingFilterProxy </filter-class> </filter> <filter-mapping> <filter-name>shiroFilter</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
2.在Spring的applicationContext.xml中添加shiro配置
<bean id="shiroFilter"
class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
<property name="securityManager" ref="securityManager" />
<property name="loginUrl" value="/login" />
<property name="successUrl" value="/login/loginSuccessFull" />
<property name="unauthorizedUrl" value="/login/unauthorized" />
<property name="filterChainDefinitions">
<value>
* = authc
/home* = anon
/ = anon
/logout = logout
/role/** = roles[admin]
/permission/** = perms[permssion:look]
/** = authcook]
/** = authc
</value>
</property>
</bean>
1.在web.xml中配置shiro的過濾器
2.在Spring的applicationContext.xml中添加shiro配置
securityManager:這個屬性是必須的。
loginUrl :沒有登錄的用戶請求需要登錄的頁面時 自動跳轉到登錄頁面,不是必須的屬性,不輸入地 址的話會自動尋找項目web項目的根目錄下的 ”/login.jsp”頁面。successUrl :登錄成功默認跳轉頁面,不配置則跳轉 至”/”。如果登陸前點擊的一個需要登錄的頁面,則在 登錄自動跳轉到那個需要登錄的頁面。不跳轉到此。
unauthorizedUrl :沒有權限默認跳轉的頁面。
|
過濾器簡稱
|
對應的
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表示需要認證(登錄)才能 使用,沒有參數
roles:例子/admins/user/**=roles[admin],參數可以寫多個, 多個時必須加上引號,並且參數之間用逗號分割,當有多 個參數時,例如admins/user/**=roles["admin,guest"],每個參 數通過才算通過,相當於hasAllRoles()方法。
perms:例子/admins/user/**=perms[user:add:*],參數可以寫 多個,多個時必須加上引號,並且參數之間用逗號分割, 例如/admins/user/**=perms["user:add:*,user:modify:*"],當 有多個參數時必須每個參數都通過才通過,想當於 isPermitedAll()方法。
rest:例子/admins/user/**=rest[user],根據請求的方法, 相當於/admins/user/**=perms[user:method] ,其中method 為post,get,delete等。
port:例子/admins/user/**=port[8081],當請求的url的端 口不是8081是跳轉到 schemal://serverName:8081?queryString,其中schmal是協 議http或https等,serverName是你訪問的host,8081是url 配置里port的端口,queryString 是你訪問的url里的?后面的參數。
authcBasic:例如/admins/user/**=authcBasic沒有參數表 示httpBasic認證
ssl:例子/admins/user/**=ssl沒有參數,表示安全的url請求, 協議為https
user:例如/admins/user/**=user沒有參數表示必須存在用戶, 當登入操作時不做檢查
注:anon,authcBasic,auchc,user是認證過濾器,
perms,roles,ssl,rest,port是授權過濾器
3. 在applicationContext.xml中添加
securityManagerper配置
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManage r"> <!-- 單realm應用。如果有多個realm,使用‘realms’屬性代替--> <property name="realm" ref="sampleRealm" /> <property name="cacheManager" ref="cacheManager" /> </bean> <bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager" />
4.配置jdbcRealm
<bean id="sampleRealm" class="org.apache.shiro.realm.jdbc.JdbcRealm"> <property name="dataSource" ref="dataSource" /> <property name="authenticationQuery" value="select t.password from my_user t where t.username = ?" /> <property name="userRolesQuery" value="select a.rolename from my_user_role t left join my_role a on t.roleid = a.id where t.username = ? " /> <property name="permissionsQuery" value="SELECT B.PERMISSION FROM MY_ROLE T LEFT JOIN MY_ROLE_PERMISSION A ON T.ID = A.ROLE_ID LEFT JOIN MY_PERMISSION B ON A.PERMISSION = B.ID WHERE T.ROLENAME = ? " /> <property name="permissionsLookupEnabled" value="true" /> <property name="saltStyle" value="NO_SALT" /> <property name="credentialsMatcher" ref="hashedCredentialsMatcher"/> </bean>
dataSource 數據源,配置不說了。
authenticationQuery 登錄認證用戶的查詢SQL,需要用登錄用 戶名作為條件,查詢密碼字段。
userRolesQuery 用戶角色查詢SQL,需要通過登錄用戶名去查 詢。查詢角色字段permissionsQuery 用戶的權限資源查詢SQL,需要用單一角色 查詢角色下的權限資源,如果存在多個角色,則是遍歷每 個角色,分別查詢出權限資源並添加到集合中。
permissionsLookupEnabled 默認false。False時不會使用permiss ionsQuery的SQL去查詢權限資源。設置為true才會去執行。 saltStyle 密碼是否加密,默認NO_SALT不加密。加密有三種選擇CRYPT,COLUMN,EXTERNAL。詳細可以去看文檔。這里按照不加密處理。
credentialsMatcher 密碼匹配規則。
下面簡單介紹:
<bean id="hashedCredentialsMatcher" class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <property name="hashAlgorithmName" value="MD5" />
<property name="storedCredentialsHexEncoded" value="true" />
<property name="hashIterations" value="1" />
</bean>
hashAlgorithmName 必須的,沒有默認值。可以有MD5或者SHA-1,如果對 密碼安全有更高要求可以用SHA-256或者更高。這里使用MD5 storedCredentialsHexEncoded 默認是true,此時用的是密碼加密用的是Hex 編碼;false時用Base64編碼 hashIterations 迭代次數,默認值是登錄JSP頁面:
<td>用戶名:</td>
<td><input type="text" name="username"></input></td>
<td>密碼:</td>
<td><input type="password" name="password"></input></td>
<td>記住我</td>
<td><input type="checkbox" name="rememberMe" /></td>
5.配置shiro注解模式
<!-- 開啟Shiro注解的Spring配置方式的beans。在 lifecycleBeanPostProcessor之后運行 --> <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvis orAutoProxyCreator" depends-on="lifecycleBeanPostProcessor" /> <bean class="org.apache.shiro.spring.security.interceptor.AuthorizationAttr ibuteSourceAdvisor"> <property name="securityManager" ref="securityManager" /> </bean>
注意:在與springMVC整合時必須放在springMVC的配置文中。 Shiro在注解模式下,登錄失敗,與沒有權限均是通過拋出異常。並且默 認並沒有去處理或者捕獲這些異常。在springMVC下需要配置捕獲相應異 常來通知用戶信息,如果不配置異常會拋出到頁面
<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionReso lver"> <property name="exceptionMappings"> <props> <prop key="org.apache.shiro.authz.UnauthorizedException"> /unauthorized </prop> <prop key="org.apache.shiro.authz.UnauthenticatedException"> /unauthenticated </prop> </props> </property> </bean>
@RequiresAuthentication
驗證用戶是否登錄,等同於方法subject.isAuthenticated() 結果為true時。
@ RequiresUser
驗證用戶是否被記憶,user有兩種含義: 一種是成功登錄的(subject.isAuthenticated() 結果為true); 另外一種是被記憶的( subject.isRemembered()結果為true)。
@ RequiresGuest
驗證是否是一個guest的請求,與@ RequiresUser完全相反。 換言之,RequiresUser == ! RequiresGuest 。 此時subject.getPrincipal() 結果為null.
@ RequiresRoles
例如:@RequiresRoles("aRoleName");
void someMethod(); 如果subject中有aRoleName角色才可以訪問方法someMethod。如果沒有這個 權限則會拋出異常AuthorizationException。
@RequiresPermissions
例如: @RequiresPermissions( {"file:read", "write:aFile.txt"} ) void someMethod();要求subject中必須同時含有file:read和write:aFile.txt的權限才能執行方法someMethod()。否則拋出異常AuthorizationException。
三.簡單擴展
1. 自定義realm:
<!--自定義的myRealm 繼承自AuthorizingRealm,也可以選擇shiro提供的 -->
<bean id="myRealm" class="com.yada.shiro.MyReam"></bean>
//這是授權方法 protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
String userName = (String) getAvailablePrincipal(principals);
//TODO 通過用戶名獲得用戶的所有資源,並把資源存入info中 …………………….
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
//這是認證方法 protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { //token中儲存着輸入的用戶名和密碼 UsernamePasswordToken upToken = (UsernamePasswordToken)token; //獲得用戶名與密碼 String username = upToken.getUsername();
String password = String.valueOf(upToken.getPassword());
//TODO 與數據庫中用戶名和密碼進行比對。比對成功則返回info,比對失敗 則拋出對應信息的異常AuthenticationException
…………………..
return info; }
2. 自定義登錄
//創建用戶名和密碼的令牌 UsernamePasswordToken token = new
UsernamePasswordToken(user.getUserName(),user.getPassWord());
//記錄該令牌,如果不記錄則類似購物車功能不能使用。 token.setRememberMe(true); //subject理解成權限對象。類似user Subject subject = SecurityUtils.getSubject();
} catch (UnknownAccountException ex) {//用戶名沒有找到。
} catch (IncorrectCredentialsException ex) {//用戶名密碼不匹配。
}catch (AuthenticationException e) {//其他的登錄錯誤
}
//驗證是否成功登錄的方法 if (subject.isAuthenticated()) {
}
3.自定義登出
4. 基於編碼的角色授權實現
Subject currentUser = SecurityUtils.getSubject();
if (currentUser.hasRole("administrator")) {
//擁有角色administrator
} else {
//沒有角色處理
}
斷言方式控制
Subject currentUser = SecurityUtils.getSubject();
//如果沒有角色admin,則會拋出異常,someMethod()也不會被執行 currentUser.checkRole(“admin");
someMethod();
5. 基於編碼的資源授權實現
Subject currentUser = SecurityUtils.getSubject();
if (currentUser.isPermitted("permssion:look")) {
//有資源權限
} else {
//沒有權限
}
斷言方式控制
Subject currentUser = SecurityUtils.getSubject();
//如果沒有資源權限則會拋出異常。 currentUser.checkPermission("permssion:look");
someMethod();
在JSP上的TAG實現
|
標簽名稱
|
標簽條件(均是顯示標簽內容)
|
|
<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>
|
默認顯示用戶名稱
|
7.默認,添加或刪除用戶的角色 或資源 ,系統不需要重啟,但是需要用戶重新登錄。 即用戶的授權是首次登錄后第一次訪問需要權限頁面時進行加載。但是需要進行控制的權限資源,是在啟動時就進行加載,如果要新增一個權限資源需要重啟系統。
8.Spring security 與apache shiro 差別: a)shiro配置更加容易理解,容易上手;security配置相對比較難懂。 b)在spring的環境下,security整合性更好。Shiro對很多其他的框架兼容性更好,號 稱是無縫集成。
c)shiro 不僅僅可以使用在web中,它可以工作在任何應用環境中。 d)在集群會話時Shiro最重要的一個好處或許就是它的會話是獨立於容器的。 e)Shiro提供的密碼加密使用起來非常方便。
9.控制精度: 注解方式控制權限只能是在方法上控制,無法控制類級別訪問。
過濾器方式控制是根據訪問的URL進行控制。允許使用*匹配URL,所以可以進行粗 粒度,也可以進行細粒度控制。
