簡介
Shiro(希羅)的前身叫JSecurity項目,始於2003年,2008年加入Apache軟件基金會併成爲Apache頂級項目。
Shiro是一個強大而靈活的開源Java安全框架,提供了認證、授權、密碼加密、會話管理等功能。
Authentication:身份認證/登錄,驗證用戶是不是擁有相應的身份;
Authorization:授權,即權限驗證,驗證某個已認證的用戶是否擁有某個權限;即判斷用戶是否能做事情,常見的如:驗證某個用戶是否擁有某個角色。或者細粒度的驗證某個用戶對某個資源是否具有某個權限;
Session Manager:會話管理,即用戶登錄後就是一次會話,在沒有退出之前,它的所有信息都在會話中;會話可以是普通JavaSE環境的,也可以是如Web環境的;
Cryptography:加密,保護數據的安全性,如密碼加密存儲到數據庫,而不是明文存儲;
Web Support:Web支持,可以非常容易的集成到Web環境;
Caching:緩存,比如用戶登錄後,其用戶信息、擁有的角色/權限不必每次去查,這樣可以提高效率;
Concurrency:shiro支持多線程應用的併發驗證,即如在一個線程中開啓另一個線程,能把權限自動傳播過去;
Testing:提供測試支持;
Run As:允許一個用戶假裝爲另一個用戶(如果他們允許)的身份進行訪問;
Remember Me:記住我,這個是非常常見的功能,即一次登錄後,下次再來的話不用登錄了。
記住一點,Shiro不會去維護用戶、維護權限;這些需要我們自己去設計/提供;然後通過相應的接口注入給Shiro即可。
核心概念
Subject: 一個安全術語,意指“當前用戶”,這裏的用戶可以指人、第三方進程等其他事物。一旦獲得Subject,你就可以立即獲得你希望用Shiro爲當前用戶做的90%的事情,如登錄、登出、訪問會話、執行授權檢查等。這裏的關鍵點是Shiro的API非常直觀,因爲它反映了開發者以‘每個用戶’思考安全控制的自然趨勢。同時,在代碼的任何地方都能很輕鬆地訪問Subject,允許在任何需要的地方進行安全操作。所有Subject都綁定到SecurityManager,與Subject的所有交互都會委託給SecurityManager;可以把Subject認爲是一個門面;SecurityManager纔是實際的執行者。
Subject subject = SecurityUtils.getSubject();
subject.login();
SecurityManager:安全管理器;shiro框架的核心,管理所有用戶更的安全操作,引用了多個內部嵌套安全組件(如Realm、Session的管理器等);
@Bean
public SecurityManager securityManager() {
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
// 設置realm
securityManager.setRealm(myShiroRealm());
// 記住我
securityManager.setRememberMeManager(rememberMeManager());
// 自定義緩存實現 使用redis
securityManager.setCacheManager(redisCacheManager());
// 自定義session管理 使用redis
securityManager.setSessionManager(sessionManager());
return securityManager;
}
Realm:域,Shiro從Realm獲取安全數據(如用戶、角色、權限),就是說SecurityManager要驗證用戶身份,那麼它需要從Realm獲取相應的用戶進行比較以確定用戶身份是否合法;也需要從Realm得到用戶相應的角色/權限進行驗證用戶是否能進行操作;可以把Realm看成DataSource,即安全數據源。Realm有兩個關鍵方法:
public class MyRealm extends AuthorizingRealm {
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
// 認證
return null;
}
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken)
throws AuthenticationException {
// 授權
return null;
}
}
Filter鏈:Shiro通過其創新的URL過濾器鏈功能支持安全特定的過濾規則,它允許你爲任何匹配的URL模式指定非正式的過濾器鏈。
使用
常規使用:https://github.com/asdf08442a/demo2-0
前後端分離:https://blog.csdn.net/u013615903/article/details/78781166
特點
- 易於理解的 Java Security API;
- 簡單的身份認證(登錄),支持多種數據源(LDAP,JDBC,Kerberos,ActiveDirectory 等);
- 對角色的簡單的籤權(訪問控制),支持細粒度的籤權;
- 支持一級緩存,以提升應用程序的性能;
- 內置的基於 POJO 企業會話管理,適用於 Web 以及非 Web 的環境;
- 異構客戶端會話訪問;
- 非常簡單的加密 API;
- 不跟任何的框架或者容器捆綁,可以獨立運行。
源碼解讀
流程
認證過程
1、通過ini配置文件創建securityManager
2、調用subject.login方法主體提交認證,提交的token
3、securityManager進行認證,securityManager最終由ModularRealmAuthenticator進行認證。
4、ModularRealmAuthenticator調用IniRealm(給realm傳入token) 去ini配置文件中查詢用戶信息
5、IniRealm根據輸入的token(UsernamePasswordToken)從 shiro.ini查詢用戶信息,根據賬號查詢用戶信息(賬號和密碼)
如果查詢到用戶信息,就給ModularRealmAuthenticator返回用戶信息(賬號和密碼)
如果查詢不到,就給ModularRealmAuthenticator返回null
6、ModularRealmAuthenticator接收IniRealm返回Authentication認證信息
如果返回的認證信息是null,ModularRealmAuthenticator拋出異常(org.apache.shiro.authc.UnknownAccountException)
如果返回的認證信息不是null(說明inirealm找到了用戶),對IniRealm返回用戶密碼 (在ini文件中存在)
和 token中的密碼 進行對比,如果不一致拋出異常(org.apache.shiro.authc.IncorrectCredentialsException)
授權流程
1、對subject進行授權,調用方法isPermitted("permission串")
2、SecurityManager執行授權,通過ModularRealmAuthorizer執行授權
3、ModularRealmAuthorizer執行realm(自定義的Realm)從數據庫查詢權限數據,調用realm的授權方法:doGetAuthorizationInfo
4、realm從數據庫查詢權限數據,返回ModularRealmAuthorizer
5、ModularRealmAuthorizer調用PermissionResolver進行權限串比對
6、如果比對後,isPermitted中"permission串"在realm查詢到權限數據中,說明用戶訪問permission串有權限,否則 沒有權限,拋出異常。
Filters
配置 縮寫 | 對應的過濾器 | 功能 |
anon | AnonymousFilter | 指定url可以匿名訪問 |
authc | FormAuthenticationFilter | 指定url需要form表單登錄,默認會從請求中獲取username 、password ,rememberMe 等參數並嘗試登錄,如果登錄不了就會跳轉到loginUrl配置的路徑。我們也可以用這個過濾器做默認的登錄邏輯,但是一般都是我們自己在控制器寫登錄邏輯的,自己寫的話出錯返回的信息都可以定製嘛. |
authcBasic | BasicHttpAuthenticationFilter | 指定url需要basic登錄 |
logout | LogoutFilter | 登出過濾器,配置指定url就可以實現退出功能,非常方便 |
noSessionCreation | NoSessionCreationFilter | 禁止創建會話 |
perms | PermissionsAuthorizationFilter | 需要指定權限才能訪問 |
port | PortFilter | 需要指定端口才能訪問 |
rest | HttpMethodPermissionFilter | 將http請求方法轉化成相應的動詞來構造一個權限字符串,這個感覺意義不大,有興趣自己看源碼的註釋 |
roles | RolesAuthorizationFilter | 需要指定角色才能訪問 |
ssl | SslFilter | 需要https請求才能訪問 |
user | UserFilter | 需要已登錄或“記住我”的用戶才能訪問 |
以上是shiro的一些Filter,如我們在filterChainDefinitions裏配置了/admin=authc,roles[admin],那麼/admin這個請求會由org.apache.shiro.web.filter.authc.FormAuthenticationFilter和org.apache.shiro.web.filter.authz.RolesAuthorizationFilter這兩個filter來處理,其中authc,roles只是filter的別名。