Shiro筆記(四)Shiro的realm認證


認證流程:

1.獲取當前Subject.調用SecurityUtils.getSubject();
2.測試當前用戶是否已經被認證,即是否已經登錄,調用Subject的isAurhenticated();
3.若沒有認證,則把用戶名和密碼封裝成UsernamePasswordToken對象.
對於B/S應用程序來說,一般用戶名和密碼是在前台表單中獲得的:

1.創建一個表單頁面.
2.把請求提交到SpringMVC的Controller.
3.獲取用戶名和密碼.

4.執行登錄:調用Subject.login(AuthenticationToken) 方法.
5.自定義Realm方法,從數據庫中獲取對應的記錄,返回給Shiro.

自定義Realm的實現:
1.繼承org.apache.shiro.realm.AuthenticatingRealm類.
2.實現doGetAuthenticationInfo(AuthenticationToken)方法.

為什么要繼承它且實現它的doGetAuthenticationInfo方法呢?可以跟進源碼查看subject.login(token)是怎樣工作的:
subject.login(token)->securityManager.login(this, token)->authenticate(token)->authenticator.authenticate(token)->在org.apache.shiro.authc.AbstractAuthenticator中的doAuthenticate(token)方法->查看執行單個認證操作doSingleRealmAuthentication(realms.iterator().next(), authenticationToken)->realm.getAuthenticationInfo(token)->getCachedAuthenticationInfo(token)->在getAuthenticationInfo方法中定義了doGetAuthenticationInfo(token),所以需要實現doGetAuthenticationInfo方法.

6.由shiro完成對密碼的比對.

數據傳輸流程解析:

在執行subject.login(token)方法后,token對象將會傳到第5步中自定義Realm中的實現的doGetAuthenticationInfo方法中的AuthenticationToken對象中,這樣就可以將token對象傳到Realm域中了,我們可以對token進行比對判斷登錄是否成功.
流程:

前台form表單提交數據->Controller->subject.login(token)->shiro域中接收到token對象.

后台數據驗證流程分析

  1. 把AuthenticationToken轉換為UsernamePasswordToken.因為我們在之前傳入Token對象的時候就是一個這個對象,所以可以強轉;

    通過用戶名把數據從數據庫取出來
    因為配置了Jedis緩存,所以先從緩存中取,取不到再去數據庫中取,在數據庫中取出后在放到緩存中
    UsernamePasswordToken authenToken = (com.yl.video.security.UsernamePasswordToken) token;

  2. 從UsernamePasswordToken中取出username;

    String userName = token.getUsername();

  3. 調用數據庫的方法,從數據庫中查詢出對應的用戶記錄,返回一個數據庫中的user對象.

    SysUser user = UserUtils.getByLoginName(userName);

  4. 若登錄失敗,拋出AuthenticationException等異常.此處只拋出一個賬戶鎖定異常.

     if (user != null) {
    
     if (Global.BOOLFALSE.equals(user.getLocked())){
     	throw new AuthenticationException("該已帳號禁止登錄.");
     	}
     }
    
  5. 根據用戶情況,構建AuthenticationInfo對象並返回.

AuthenticationInfo對象是一個接口對象,常用SimpleAuthenticationInfo對象來實現.
創建一個返回的info對象:

return new SimpleAuthenticationInfo(new Principal(user, authenToken.isMobileLogin()), String.valueOf(user.getPassword()), ByteSource.Util.bytes(userName+user.getSalt()), getName());

三個參數的解釋:

  1. principal:認證的實體信息,可以是傳過來的user對象,也可以是username等;
  2. credentials:數據庫中的密碼;
  3. realmName:當前Realm對象的name,調用父類的getName()方法即可.

注意:需要對shiro進行登出操作,否則會有登錄成功后再登錄錯誤的對象會造成仍然能登錄的情況

密碼比對分析

通過AuthenticatingRealm 的credentialsMatcher 屬性來進行密碼比對 !

  1. 把密碼字符串加密成MD5;
  2. 替換當前Realm的credentialsMatcher屬性,直接使用HashedCredentialsMatcher對象,並設置加密算法即可.

如何替換:
在對密碼加密分析的時候,要對兩個密碼進行分析,一個是從前台獲取到的密碼,另一個是在數據庫中獲取到的密碼,分別對兩個密碼進行鹽值加密:

  1. 對從前台傳過來的token對象: 通過在配置文件中配置加密算法即可自動將密碼加密成想要的結果:








  2. 從數據庫中傳過來的對象: 因為在shiro的加密中,最后對數據加密是調用了new SimpleHash(hashAlogorithnName,credentials,salt,hashIterations)方法,所以對數據庫中的密碼直接進行調用此方法即可. 參數分別為(加密方式,加密的密碼,鹽值,加密次數).

如何使用鹽值加密

  1. 為什么要對密碼進行加鹽:
    在realm進行密碼比對的過程中,當密碼相同的時候,用戶名無須正確只要密碼比對成功即可登錄成功,所以要讓密碼唯一,所以可以對密碼加鹽,其中鹽值必須是唯一的.
  2. 如何對密碼進行鹽值加密:
    1. 在doGetAuthenticationInfo方法返回值創建SimpleAuthenticationInfo對象的時候,需使用SimpleAuthenticationInfo(principal,credentials,credentialsSalt,realmName)構造器.
    2. 使用ByteSource.Util.bytes()來計算鹽值.
    3. 鹽值要唯一:一般使用隨機字符串或id
    4. 使用new SimpleHash(hashAlogorithnName,credentials,salt,hashIterations)來計算鹽值加密后的值.

多realm認證

多realm認證原理:

多realm認證是通過ModularRealmAuthenticator對象進行認證的,我們可以在spring-shiro中配置多個realm,並將多個bean統一交給ModularRealmAuthenticator進行管理,然后在SecurityManager中配置ModularRealmAuthenticator來進行實現多realm認證的效果。

多realm的認證配置:

多realm配置1
多realm配置2
多realm配置3

在多realm配置的時候一般將兩個或多個realms放在securityManager中而不是放在authenticator中,如下圖:

這樣的好處是當授權的時候比較方便。

多realm的認證策略


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM