什么是Shiro?
Apache Shiro是Java的一個安全框架。目前,使用Apache Shiro的人越來越多,因為它相當簡單,對比Spring Security,可能沒有Spring Security做的功能強大,但是在實際工作時可能并不需要那么復雜的東西,所以使用小而簡單的Shiro就足夠了。對于它倆到底哪個好,這個不必糾結(jié),能更簡單的解決項目問題就好了。
Shiro可以非常容易的開發(fā)出足夠好的應用,其不僅可以用在JavaSE環(huán)境,也可以用在JavaEE環(huán)境。Shiro可以幫助我們完成:認證、授權、加密、會話管理、與Web集成、緩存等。
Shiro架構(gòu)有三個主要概念, Subject, SecurityManager, Realms

Subject:主體,可以看到主體可以是任何可以與應用交互的“用戶”;
SecurityManager:是Shiro的心臟;所有具體的交互都通過SecurityManager進行控制;它管理著所有Subject、且負責進行認證和授權、及會話、緩存的管理。
Authenticator:認證器,負責主體認證的,這是一個擴展點,如果用戶覺得Shiro默認的不好,可以自定義實現(xiàn);其需要認證策略(Authentication Strategy),即什么情況下算用戶認證通過了;
Authorizer:授權器,或者訪問控制器,用來決定主體是否有權限進行相應的操作;即控制著用戶能訪問應用中的哪些功能;
Realm:可以有1個或多個Realm,可以認為是安全實體數(shù)據(jù)源,即用于獲取安全實體的;可以是JDBC實現(xiàn),也可以是文件實現(xiàn),或者內(nèi)存實現(xiàn)等等;注意:Shiro不知道你的用戶/權限存儲在哪及以何種格式存儲;所以我們一般在應用中都需要實現(xiàn)自己的Realm;
SessionManager:如果寫過Servlet就應該知道Session的概念,Session需要有人去管理它的生命周期,這個組件就是SessionManager;而Shiro并不僅僅可以用在Web環(huán)境,也可以用在如普通的JavaSE環(huán)境等環(huán)境;Shiro就抽象了一個自己的Session來管理主體與應用之間交互的數(shù)據(jù);可以實現(xiàn)分布式的會話管理;
SessionDAO:DAO大家都用過,數(shù)據(jù)訪問對象,用于會話的CRUD,比如我們想把Session保存到數(shù)據(jù)庫,那么可以實現(xiàn)自己的SessionDAO,通過如JDBC寫到數(shù)據(jù)庫;比如想把Session放到redis中,可以實現(xiàn)自己的redis? SessionDAO;另外SessionDAO中可以使用Cache進行緩存,以提高性能;
CacheManager:緩存控制器,來管理如用戶、角色、權限等的緩存的;因為這些數(shù)據(jù)基本上很少去改變,放到緩存中后可以提高訪問的性能
Cryptography:密碼模塊,Shiro提高了一些常見的加密組件用于如密碼加密/解密的。
下面是Shiro的一個簡單登錄認證Demo(JavaSE環(huán)境)
首先了解一下認證的流程分析:
1、調(diào)用subject.login方法進行登錄,其會自動委托給securityManager.login方法進行登錄;
2、securityManager通過Authenticator(認證器)進行認證;
3、Authenticator的實現(xiàn)ModularRealmAuthenticator調(diào)用realm從ini配置文件取用戶真實的賬號和密碼,這里使用的是IniRealm(shiro自帶,相當于數(shù)據(jù)源);
4、IniRealm先根據(jù)token中的賬號去ini中找該賬號,如果找不到則給ModularRealmAuthenticator返回null,如果找到則匹配密碼,匹配密碼成功則認證通過。
5、最后調(diào)用Subject.logout進行退出操作。


認證操作:
模擬準備一些用戶

代碼實現(xiàn):

用戶名不存在時拋出的異常:

密碼錯誤時拋出的異常:

認證操作源碼解析:

自定義Realm:


Realm僅僅是提供數(shù)據(jù)給認證器做相關的一些判斷,本身自己不會做密碼判斷,因為有對應的憑證匹配器去做判斷.
在Shiro框架中提供了兩個加密工具

在項目中使用時需要添加配置文件, 定義一個憑證匹配器,注入到Realm, 再把Realm設置到SecurityManager上面就可以生效了,

授權流程:和認證流程大體相似,核心都是要構(gòu)造SecurityManager環(huán)境

授權方式主要有三種:編程式, 注解式, JSP標簽
第一種: 通過寫if/else授權代碼塊完成
Subject subject = SecurityUtils.getSubject();?
if(subject.hasRole(“admin”)) {?
? ? //有權限?
} else {?
? ? //無權限?
}?
第二種: 通過在執(zhí)行的Java方法上放置相應的注解完成
@RequiresRoles("admin")?
public void hello() {?
? ? //有權限?
}
第三種 : 在JSP頁面通過相應的標簽完成
<shiro:hasRole name="admin">
? ? ? ? <!--有權限-->
</shiro:hasRole>
權限字符串規(guī)則:
在ini文件中用戶、角色、權限的配置規(guī)則是:“用戶名=密碼,角色1,角色2...” “角色=權限1,權限2...”,首先根據(jù)用戶名找角色,再根據(jù)角色找權限,角色是權限集合。
權限字符串的規(guī)則是:“資源標識符:操作:資源實例標識符”,意思是對哪個資源的哪個實例具有什么操作,“:”是資源/操作/實例的分割符,權限字符串也可以使用*通配符。
例子:
用戶創(chuàng)建權限:user:create,或user:create:*?
用戶修改實例001的權限:user:update:001
用戶實例001的所有權限:user:*:001
操作步驟:
1.使用ini的方式來配置用戶,角色,權限
2.在認證成功之后進行權限/角色判斷

常用的幾種判斷方式

1.補充自定義realm的授權方法

2.在認證后進行角色或權限的驗證


授權流程分析:

1、首先調(diào)用Subject.isPermitted*/hasRole*接口,其會委托給SecurityManager,而SecurityManager接著會委托給Authorizer
2、Authorizer是真正的授權者
3、在進行授權之前,其會調(diào)用相應的Realm獲取Subject相應的角色/權限;
4、Authorizer會判斷Realm的角色/權限是否包含該權限,如果有多個Realm,會委托給ModularRealmAuthorizer進行循環(huán)判斷,如果匹配如isPermitted*/hasRole*會返回true,否則返回false表示授權失敗。