簡介
Apache Shiro是Java的一個安全框架。目前,使用Apache Shiro的人越來越多,因為它相當簡單,對比Spring Security,可能沒有Spring Security做的功能強大,但是在實際工作時可能並不需要那麼複雜的東西,所以使用小而簡單的Shiro就足夠了。對於它倆到底哪個好,這個不必糾結,能更簡單的解決專案問題就好了。
Shiro可以非常容易的開發出足夠好的應用,其不僅可以用在JavaSE環境,也可以用在JavaEE環境。Shiro可以幫助我們完成:認證、授權、加密、會話管理、與Web整合、快取等,在此我僅僅介紹我們公司使用的認證、授權、加密功能,對於其他功能,小夥伴可以發揮一下自學能力呦
在此讓我們來了解一些shiro的一些基本的術語
-
Authentication:
身份認證/登入,驗證使用者是不是擁有相應的身份;
-
Authorization:
授權,即許可權驗證,驗證某個已認證的使用者是否擁有某個許可權;即判斷使用者是否能做事情,常見的如:驗證某個使用者是否擁有某個角色。或者細粒度的驗證某個使用者對某個資源是否具有某個許可權;
-
Cryptography:
加密,保護資料的安全性,如密碼加密儲存到資料庫,而不是明文儲存;
-
Subject:
主體,代表了當前“使用者”,這個使用者不一定是一個具體的人,與當前應用互動的任何東西都是Subject,如網路爬蟲,機器人等;即一個抽象概念;所有Subject都繫結到SecurityManager,與Subject的所有互動都會委託給SecurityManager;可以把Subject認為是一個門面;SecurityManager才是實際的執行者;
-
SecurityManager:
相當於SpringMVC中的DispatcherServlet或者Struts2中的FilterDispatcher;是Shiro的心臟;所有具體的互動都通過SecurityManager進行控制;它管理著所有Subject、且負責進行認證和授權、及會話、快取的管理
-
Realm:
域,Shiro從從Realm獲取安全資料(如使用者、角色、許可權),就是說SecurityManager要驗證使用者身份,那麼它需要從Realm獲取相應的使用者進行比較以確定使用者身份是否合法;也需要從Realm得到使用者相應的角色/許可權進行驗證使用者是否能進行操作;可以把Realm看成DataSource,即安全資料來源。
-
token
token相當於一個令牌,是將使用者的一些資訊(如賬號、密碼、等)經過雜湊然後生成一個無意義的字串儲存在資料庫或者redis,雜湊不可逆,使用者登入時只能通過重新雜湊然後得到串和資料庫中的串做比較,看是否相同判定賬號密碼是否正確
shiro執行流程
- 首先,我們從外部來看Shiro吧,即從應用程式角度的來觀察如何使用Shiro完成工作
- 應用程式碼通過Subject來進行認證和授權,而Subject又委託給SecurityManager;
- 我們需要給Shiro的SecurityManager注入Realm,從而讓SecurityManager能得到合法的使用者及其許可權 進行判斷。
- 對於realm的詳解
相信看完上面的工作流程圖大家一定會產生一個疑問–>為什麼要realm?請看下文分析。。。。
shiro作為一個安全授權框架,對於使用者安全登入上,怎樣的使用者是安全的?怎怎樣的使用者是可以進入的?樣的使用者該擁有什麼樣的許可權?相信這些只有開發者才知道,realm正是shiro留給開發者用於自定義使用者登入驗證和授權認證的一個類,我們可以通過實現Realm介面建立一個自定義的realm類,用於自定義使用者登入驗證方式(AuthenticationInfo來完成)和授權驗證(AuthorizationInfo來完成)
登入驗證
相信大家通過上面的講解對shiro已經有了一些基本的瞭解,那麼接下來我將通過我們公司封裝的shiro框架為例,向大家揭祕登入和授權功能
- 編寫TokenFilter來進行登入驗證
- 在配置檔案裡面配置需要進行驗證的一些mappering
- 讓我們來看一下filter裡面主要的一個類
- 首先他呼叫了一個gettoken方法,返回了一個Token,讓我們看一下gettoken方法
通過檢視程式碼,我們知道這個token來自於請求域,來自於使用者填寫的資訊
- 再回到filter中我們會發現這麼一句程式碼
boolean loginSuccess = this.login(new Token(token));
將獲得的token傳入到一個login方法中,接下來讓我們順著這裡往下走,來到了另一個login,裡面有這麼一句–>subject.login(token);
- 進入subject.login(token),順著一直走我們會發現這麼一個類
在這個方法裡面我們可以發現這麼一句–>info = authenticate(token);,我們可以發現這就是在間接地呼叫relam類裡面的我們自動以的驗證方法
- 讓我們進入relam的doGetAuthenticationInfo
我們會發現他是通過使用者資料為key在redis中嘗試獲取有沒有對應的value,來證明是否這個使用者曾經註冊過,或者賬號密碼和一些資訊是否正確
授權
關於授權的一些概念
主體
主體,即訪問應用的使用者,在Shiro中使用Subject代表該使用者。使用者只有授權後才允許訪問相應的資源。
資源
在應用中使用者可以訪問的任何東西,比如訪問JSP頁面、檢視/編輯某些資料、訪問某個業務方法、列印文字等等都是資源。使用者只要授權後才能訪問。
許可權
安全策略中的原子授權單位,通過許可權我們可以表示在應用中使用者有沒有操作某個資源的權力。即許可權表示在應用中使用者能不能訪問某個資源,如:
訪問使用者列表頁面
檢視/新增/修改/刪除使用者資料(即很多時候都是CRUD(增查改刪)式許可權控制)
列印文件等等。。。
如上可以看出,許可權代表了使用者有沒有操作某個資源的權利,即反映在某個資源上的操作允不允許,不反映誰去執行這個操作。所以後續還需要把許可權賦予給使用者,即定義哪個使用者允許在某個資源上做什麼操作(許可權),Shiro不會去做這件事情,而是由實現人員提供。
Shiro支援粗粒度許可權(如使用者模組的所有許可權)和細粒度許可權(操作某個使用者的許可權,即例項級別的),後續部分介紹。
角色
角色代表了操作集合,可以理解為許可權的集合,一般情況下我們會賦予使用者角色而不是許可權,即這樣使用者可以擁有一組許可權,賦予許可權時比較方便。典型的如:專案經理、技術總監、CTO、開發工程師等都是角色,不同的角色擁有一組不同的許可權。
隱式角色:
即直接通過角色來驗證使用者有沒有操作許可權,如在應用中CTO、技術總監、開發工程師可以使用印表機,假設某天不允許開發工程師使用印表機,此時需要從應用中刪除相應程式碼;再如在應用中CTO、技術總監可以檢視使用者、檢視許可權;突然有一天不允許技術總監檢視使用者、檢視許可權了,需要在相關程式碼中把技術總監角色從判斷邏輯中刪除掉;即粒度是以角色為單位進行訪問控制的,粒度較粗;如果進行修改可能造成多處程式碼修改。
顯示角色:
在程式中通過許可權控制誰能訪問某個資源,角色聚合一組許可權集合;這樣假設哪個角色不能訪問某個資源,只需要從角色代表的許可權集合中移除即可;無須修改多處程式碼;即粒度是以資源/例項為單位的;粒度較細。、
授權方式
Shiro支援三種方式的授權:
1.程式設計式:通過寫if/else授權程式碼塊完成:
Java程式碼
Subject subject = SecurityUtils.getSubject();
if(subject.hasRole(“admin”)) {
//有許可權
} else {
//無許可權
}
註解式:通過在執行的Java方法上放置相應的註解完成:
Java程式碼 收藏程式碼
@RequiresRoles("admin")
public void hello() {
//有許可權
}
沒有許可權將丟擲相應的異常;
JSP/GSP標籤:在JSP/GSP頁面通過相應的標籤完成:
Java程式碼
<shiro:hasRole name="admin">
<!— 有許可權 —>
</shiro:hasRole>
我們 公司如何用shiro做許可權
- 我們公司採用註解的方法來進行許可權控制
這是我從公司一個勘察專案中截下的一段程式碼可以看到–>@RequiresRoles。。。。
它的意思就是後面的角色裡只要使用者有其中一個角色就可以使用這個方法
- 讓我們來看realm裡面的AuthorizationInfo方法(這個方法用於做許可權的認定)
我們可以發現它先拿到一個userid,然後通過userid為key在redis中尋找value,然後將許可權資訊放入info返回,對此大家一定很好奇他在redis中拿了什麼
- 讓我們來看看它在redis中拿了什麼
我們檢視redis發現它拿了一個數字
- 這個數字就代表著他的角色,而每個角色有每個角色的許可權
以上,就是今天的全部內容。
增鑫
蘆葦科技Java開發工程師
蘆葦科技-廣州專業軟體外包服務公司
提供微信小程式、APP應用研發、UI設計等專業服務,專注於網際網路產品諮詢、品牌設計、技術研發等領域、
訪問 www.talkmoney.cn 瞭解更多
萬能說明書 | 早起日記Lite | 凹凸桌布 | 言財