之間工作中曾經用到過shiro這個權限控制的框架,之前一直都是停留在用的方面,沒有過多的 去理解這方面的知識,現在有時間,專門研究了一下這個Shiro權限的框架使用。
Shiro是什么?
Apache Shiro是一個強大而靈活的開源安全框架,它干凈利落地處理身份認證,授權,企業會話管理和加密。
Apache Shiro的首要目標是易于使用和理解。安全有時候是很復雜的,甚至是痛苦的,但它沒有必要這樣。框架應該盡可能掩蓋復雜的地方,露出一個干凈而直觀的API,來簡化開發人員在使他們的應用程序安全上的努力。
因為很多時候很多人比較喜歡使用Spring提供的Spring Security和Shiro來進行對比,我們也對比一下這個內容。
Apache Shiro是JAVA的一個安全框架。
目前,使用Apache Shiro的人越來越多,因為它相當簡單,對比Spring Security,可能沒有Spring Security做的功能強大,但是在實際工作時可能并不需要那么復雜的東西,所以使用小而簡單的Shiro就足夠了。
所以,我們工作中很多時候都是直接使用的Shiro來進行安全控制。
我們介紹完了之后,在看看Shiro有什么用處?
Shiro作用
- 驗證用戶來核實他們的身份
- 對用戶執行訪問控制
比如說我們可以用來判斷一個用戶是否被分配了一個安全的角色。然后來判斷這個人到底在項目中能有什么權限來處理, 意思就是假如說有2個人,一個是管理員,他有增刪改查的功能,而另外一個用戶就是只又查的功能,沒有增刪改的功能, 通過Shiro來進行控制,就能達到這種效果。
我們可以看一下Apache官網上對Shiro,它都包含哪些功能。
我們看看它每一個模塊代表的是什么意思
Authentication:認證,有時也簡稱為“登錄”,這是一個證明用戶是他們所說的他們是誰的行為。
Authorization:授權,訪問控制的過程,也就是絕對“誰”去訪問“什么” 授權用于回答安全問題,例如“用戶是否允許編輯帳戶”,“該用戶是否允許查看此網頁”,“該用戶是否可以訪問”到這個按鈕?“這些都是決定用戶有權訪問的決定,因此都代表授權檢查。
Cryptography:密碼術是通過隱藏信息或將其轉換為無意義來保護信息免受不良訪問的做法,因此沒有其他人可以閱讀它。Shiro專注于密碼學的兩個核心要素:使用公鑰或私鑰加密數據的密碼,以及對密碼等數據進行不可逆轉加密的哈希(也稱為消息摘要)。
Shiro Cryptography的主要目標是采用傳統上非常復雜的領域,并在提供強大的密碼學功能的同時使其他人輕松實現。
Session Management:Session會話,會話是您的用戶在使用您的應用程序時攜帶一段時間的數據桶。傳統上,會話專用于Web或EJB環境。不再!Shiro支持任何應用程序環境的會話。此外,Shiro還提供許多其他強大功能來幫助您管理會話。
Web Support:Shiro的web支持的API能夠輕松地幫助保護 Web 應用程序。主要就是用來對Web程序進行一個好的支持的。
Caching:緩存,他是Apache Shiro中的第一層公民,來確保安全操作快速而又高效。
Concurrency:shiro利用它的并發特性來支持多線程應用程序
Testing:測試支持的存在來幫助你編寫單元測試和集成測試,并確保你的能夠如預期的一樣安全。
“Run As”:其實這個就是有是有允許一個用戶假設為另外一個用戶身份的功能,有時候在管理腳本的時候很有效果
Remember Me:在會話中記住用戶的身份,所以他們只需要在強制時候登錄。
Shiro核心
Shiro其實是有三大核心組件的,Subject、SecurityManager和Realms。
Subject:Subject實質上是一個當前執行用戶的特定的安全“視圖”。鑒于”User”一詞通常意味著一個人,而一個Subject可以是一個人, 但它還可以代表第三方服務,daemon account,cron job,或其他類似的任何東西——基本上是當前正與軟件進行交互的任何東西。 所有Subject實例都被綁定到(且這是必須的)一個SecurityManager上。當你與一個Subject交互時,那些交互作用轉化為與SecurityManager交互的特定subject的交互作用。 我們可以把Subject認為是一個門面,SecurityManager才是真正的執行者。
SecurityManager:安全管理器,也就是說所有與安全有關的操作都會與SecurityManager進行交互,而且他管理這Subject,它其實是Shiro的核心 是Shiro架構的心臟。并作為一種“保護傘”對象來協調內部的安全組件共同構成一個對象圖。
Realms: 域,Shiro從從Realm獲取安全數據(如用戶、角色、權限),就是說SecurityManager要驗證用戶身份,那么它需要從Realm獲取相應的用戶進行比較以確定用戶身份是否合法;也需要從Realm得到用戶相應的角色/權限進行驗證用戶是否能進行操作;可以把Realm看成DataSource,即安全數據源。
當配置Shiro時,你必須指定至少一個Realm用來進行身份驗證和/或授權。SecurityManager可能配置多個Realms,但至少有一個是必須的。
我們可以通過一個簡單的登錄來看shiro對權限的控制。
我們就通過圖解來理解一下,然后寫個簡單的代碼
上圖是對shiro角色權限的設計,
而接下來我們就可以看一下它具體的登錄圖解了
我解釋一下這個圖。
1、登陸操作 攜帶用戶名密碼給subject,subject調用自己的登陸方法傳遞用戶名和密碼給權限管理器,權限管理器將用戶名密碼傳遞給開發人員編寫的realm的認證方法,realm根據用戶名到數據庫中查找是否存在該用戶,若存在將認證信息存入到session中
/*
* 參數1:登陸標識
* 參數2:正確的密碼
* 參數3:認證|授權器的名字
*/
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), this.getClass().getName());
2、權限管理器會自動判斷傳遞的密碼與正確密碼是否一致
3、訪問3類資源(頁面) 過濾器尋找權限管理器判斷該用戶是否擁有xxx權限,權限管理器從session中取出認證信息對象,返回給realm,realm判斷該用戶擁有什么權限,封裝到授權信息中返回給權限管理器,權限管理器將判斷的結果返回給過濾器
4、訪問3類資源(xxx添加需要訪問service)(對于過濾器來說屬于2類資源),在執行方法時,會到達前置通知(esrvice方法上添加注解@RequiresPermissions(“courier:list”)),權限通知尋找權限管理器判斷該用戶是否擁有xxx權限,權限管理器從session中取出認證信息對象,返回給realm,realm判斷該用戶擁有什么權限,封裝到授權信息中返回給權限管理器,權限管理器將判斷的結果返回給權限通知
其實簡單來說 /userAction_login ———->請求先到達權限過濾器shiroFilter,先判斷是幾類資源
登錄屬于一類資源直接放行到————>userActon中(userAction中調用執行subject對象(使用入口是一個操作入口對象,里面有登陸方法,登出方法,獲取當前對象方法)的登陸方法subject.login方法(攜帶著用戶名,密碼)
————>subject對象調用 securityManager的login方法 權限管理器不能判斷用戶和密碼是對的需要
————>ream認證授權器(開發人員編寫,判斷用戶名是否存在,擁有什么權限)————>處理完后把認證信息對象返回給securityManager()如果認證信息沒有問題,權限管理器會把認證信息存入session(證明認證登陸過了)
可以自定義一個Realm;
@Service("MyRealm")
public class MyRealm extends AuthorizingRealm{ //父類接口Realm
@Autowired
private UserDao ud;
@Autowired
private RoleService rs;
@Autowired
private PermissionService ps;
@Override
//授權
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
User user = (User) principals.getPrimaryPrincipal();
SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
List<Role> roles = rs.findByUser(user);
if(roles != null && roles.size() > 0){
for (Role role : roles) {
info.addRole(role.getKeyword());
}
}
List<Permission> permissions = ps.findByUser(user);
if(permissions != null && permissions.size() > 0) {
for (Permission permission : permissions) {
info.addStringPermission(permission.getKeyword());
}
}
return info;
}
@Override
//認證
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken t) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) t;
String username = token.getUsername();
User user = ud.findByUsername(username);
if(user != null){
/*
* 參數1:登陸標識
* 參數2:正確的密碼
* 參數3:認證|授權器的名字
*/
SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user, user.getPassword(), this.getClass().getName());
//ActionContext.getContext().getSession().put("loginUser", user);
return info;
} else {
return null;
}
}
}
登陸完以后訪問頁面資源(頁面資源屬于三類資源需要權限),
shiroFilter(已經配置了哪些資源是一類哪些資源是三類)
————>訪問權限管理器,找權限管理器判斷是否有xxx權限(權限管理器本身不能做出判斷),權限管理器把之前登陸時保存在session中的認證信息取出
交給————>realm判斷(realm中認證方法是登陸時候調用的),realm查詢數據庫獲得權限,把權限信息返還給————>權限管理器。
權限管理器根據realm的授權信息判斷是否擁有xxx權限, 判斷后把結果通知給————>權限管理器,權限管理器ShiraFilter 如果沒有權限跳轉到響應頁面。
這其實就是一個簡單的shiro框架的設計,可能個人設計的有點小毛病,只是一個測試,大家自行體會
總結
Shiro是一個功能很齊全的框架,使用起來也很容易,總結一下 三大核心內容:
- Subject
- SecurityManager
- Realms
Shiro 功能強大、且 簡單、靈活。是Apache 下的項目比較可靠,且不跟任何的框架或者容器綁定,可以獨立運行
所以這個權限控制框架,大家理解了么?有想法的咱們可以共同交流一下。