shiro身份验证
身份驗證,即在應(yīng)用中誰能證明他就是他本人。一般提供如他們的身份ID一些標(biāo)識信息來表明他就是他本人,如提供身份證,用戶名/密碼來證明。
在shiro中,用戶需要提供principals?(身份)和credentials(證明)給shiro,從而應(yīng)用能驗證用戶身份:
principals:身份,即主體的標(biāo)識屬性,可以是任何東西,如用戶名、郵箱等,唯一即可。一個主體可以有多個principals,但只有一個Primary principals,一般是用戶名/密碼/手機號。
credentials:證明/憑證,即只有主體知道的安全值,如密碼/數(shù)字證書等。
最常見的principals和credentials組合就是用戶名/密碼了。
?
例如在AuthenticationToken 就只提供了兩個方法,分別獲取身份和憑證。AuthenticationToken 的使用的實現(xiàn)一般就是UsernamePasswordToken,但是可以自定義實現(xiàn),例如JWT token。
public interface AuthenticationToken extends Serializable { Object getPrincipal();Object getCredentials();}?
對于身份驗證的流程我們同樣可以從外部和內(nèi)部兩個角度來看
一、外部實現(xiàn)流程
1.、首先準(zhǔn)備一些用戶身份/憑據(jù)(shiro.ini)
Java代碼??此處使用ini配置文件,通過[users]指定了兩個主體:zhang/123、wang/123。
??
2、測試用例
@Test public void testHelloworld() { //1、獲取SecurityManager工廠,此處使用Ini配置文件初始化SecurityManager Factory<org.apache.shiro.mgt.SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini"); //2、得到SecurityManager實例 并綁定給SecurityUtils org.apache.shiro.mgt.SecurityManager securityManager = factory.getInstance(); SecurityUtils.setSecurityManager(securityManager); //3、得到Subject及創(chuàng)建用戶名/密碼身份驗證Token(即用戶身份/憑證) Subject subject = SecurityUtils.getSubject(); UsernamePasswordToken token = new UsernamePasswordToken("zhang", "123"); try { //4、登錄,即身份驗證 subject.login(token); } catch (AuthenticationException e) { //5、身份驗證失敗 } Assert.assertEquals(true, subject.isAuthenticated()); //斷言用戶已經(jīng)登錄 //6、退出 subject.logout(); }2.1、首先通過new IniSecurityManagerFactory并指定一個ini配置文件來創(chuàng)建一個SecurityManager工廠;
2.2、接著獲取SecurityManager并綁定到SecurityUtils,這是一個全局設(shè)置,設(shè)置一次即可;
2.3、通過SecurityUtils得到Subject,其會自動綁定到當(dāng)前線程;如果在web環(huán)境在請求結(jié)束時需要解除綁定;然后獲取身份驗證的Token,如用戶名/密碼;
2.4、調(diào)用subject.login方法進行登錄,其會自動委托給SecurityManager.login方法進行登錄;
2.5、如果身份驗證失敗請捕獲AuthenticationException或其子類,常見的如:?DisabledAccountException(禁用的帳號)、LockedAccountException(鎖定的帳號)、UnknownAccountException(錯誤的帳號)、ExcessiveAttemptsException(登錄失敗次數(shù)過多)、IncorrectCredentialsException?(錯誤的憑證)、ExpiredCredentialsException(過期的憑證)等,具體請查看其繼承關(guān)系;對于頁面的錯誤消息展示,最好使用如“用戶名/密碼錯誤”而不是“用戶名錯誤”/“密碼錯誤”,防止一些惡意用戶非法掃描帳號庫;
2.6、最后可以調(diào)用subject.logout退出,其會自動委托給SecurityManager.logout方法退出。
?
3.Realm實現(xiàn)
org.apache.shiro.realm.Realm接口如下:?
String getName(); //返回一個唯一的Realm名字 boolean supports(AuthenticationToken token); //判斷此Realm是否支持此Token AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException; //根據(jù)Token獲取認(rèn)證信息自定義Realm實現(xiàn):
public class MyRealm1 implements Realm { @Override public String getName() { return "myrealm1"; } @Override public boolean supports(AuthenticationToken token) { //僅支持UsernamePasswordToken類型的Token return token instanceof UsernamePasswordToken; } @Override public AuthenticationInfo getAuthenticationInfo(AuthenticationToken token) throws AuthenticationException { String username = (String)token.getPrincipal(); //得到用戶名 String password = new String((char[])token.getCredentials()); //得到密碼 if(!"zhang".equals(username)) { throw new UnknownAccountException(); //如果用戶名錯誤 } if(!"123".equals(password)) { throw new IncorrectCredentialsException(); //如果密碼錯誤 } //如果身份認(rèn)證驗證成功,返回一個AuthenticationInfo實現(xiàn); return new SimpleAuthenticationInfo(username, password, getName()); } }?
二、從內(nèi)部實現(xiàn)原理來看
流程如下:
1、首先調(diào)用Subject.login(token)進行登錄,其會自動委托給Security Manager,調(diào)用之前必須通過SecurityUtils. setSecurityManager()設(shè)置;
2、SecurityManager負(fù)責(zé)真正的身份驗證邏輯;它會委托給Authenticator進行身份驗證;
3、Authenticator才是真正的身份驗證者,Shiro API中核心的身份認(rèn)證入口點,此處可以自定義插入自己的實現(xiàn);
4、Authenticator可能會委托給相應(yīng)的AuthenticationStrategy進行多Realm身份驗證,默認(rèn)ModularRealmAuthenticator會調(diào)用AuthenticationStrategy進行多Realm身份驗證;
5、Authenticator會把相應(yīng)的token傳入Realm,從Realm獲取身份驗證信息,如果沒有返回/拋出異常表示身份驗證失敗了。此處可以配置多個Realm,將按照相應(yīng)的順序及策略進行訪問。
?
摘自:第二章 身份驗證——《跟我學(xué)Shiro》
轉(zhuǎn)載于:https://www.cnblogs.com/xiangkejin/p/8973678.html
總結(jié)
- 上一篇: 从Github开源项目《云阅》所学到的知
- 下一篇: 手风琴切换效果