Shiro入門學習---使用自定義Realm完成認證|練氣中期

賴柄灃發表於2020-10-06

寫在前面

在上一篇文章《shiro認證流程原始碼分析--練氣初期》當中,我們簡單分析了一下shiro的認證流程。不難發現,如果我們需要使用其他資料來源的資訊完成認證操作,我們需要自定義Realm繼承AuthorizingRealm類,並實現兩個方法,分別對應授權和認證。

在這一篇文章當中,我們將介紹如何自定義Realm物件,完成認證資訊資料來源的切換。

自定義Reaml

/**自定義Realm物件
 * @author 賴柄灃 bingfengdev@aliyun.com
 * @version 1.0
 * @date 2020/10/4 11:00
 */
public class MySqlRealm extends AuthorizingRealm {

    /**授權,今天暫不實現
     * @author 賴柄灃 bingfengdev@aliyun.com
     * @date 2020-10-04 11:01:50
     * @param principalCollection
     * @return org.apache.shiro.authz.AuthorizationInfo
     * @throws AuthenticationException
     * @version 1.0
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {

        return null;
    }

    /**認證
     * @author 賴柄灃 bingfengdev@aliyun.com
     * @date 2020-10-04 11:01:50
     * @param authenticationToken
     * @return org.apache.shiro.authz.AuthorizationInfo
     * @throws AuthenticationException
     * @version 1.0
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        // 1. 從token中獲取使用者名稱
        String principal = (String) authenticationToken.getPrincipal();

        //2. 根據使用者名稱查詢資料庫(模擬)
        if (principal == "xiangbei") {
            AuthenticationInfo authInfo = new SimpleAuthenticationInfo("xiangbei","123",this.getName());
            return authInfo;
        }
        return null;
    }
}

在認證器中使用自定義Realm進行認證

/**認證管理器
 * @author 賴柄灃 bingfengdev@aliyun.com
 * @version 1.0
 * @date 2020/10/4 11:11
 */
public class CurrentSystemAuthenticator {
    private DefaultSecurityManager securityManager;
    public CurrentSystemAuthenticator() {
        //建立安全管理器
        securityManager = new DefaultSecurityManager();

        //設定自定義realm
        this.securityManager.setRealm(new MySqlRealm());

        //將安全管理器設定到安全工具類中
        SecurityUtils.setSecurityManager(securityManager);

    }

    public void authenticate(String username,String password){
        //獲取當前登入主題
        Subject subject = SecurityUtils.getSubject();

        //生成toeken
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);

        //進行認證
        try {
            subject.login(token);
        }catch (UnknownAccountException | IncorrectCredentialsException e) {
            System.out.println("使用者名稱或密碼不正確");
        }


        //列印認證狀態
        if (subject.isAuthenticated()){
            System.out.println(token.getPrincipal()+" 認證通過!");
        }else {
            System.out.println(token.getPrincipal()+" 認證未通過!");
        }


    }
}

進行測試

認證通過的情況

用例程式碼

/**測試認證
 * @author 賴柄灃 bingfengdev@aliyun.com
 * @version 1.0
 * @date 2020/9/21 0:49
 */
public class TestAuthenticator {
    private  Authenticator authenticator=null;

    @Before
    public void init() {
        authenticator = new Authenticator();
    }

    @Test
    public void testAuth(){

        authenticator.authenticate("xiangbei","123");
    }
}

輸出

xiangbei 認證通過!

認證不通過的情況

認證不通過的情況在shiro當中分為幾種情況,具體可以檢視我的上一篇文章《shiro認證流程原始碼分析--練氣初期》 關於shiro認證異常的分析,常用的有如下幾種:

  1. 賬戶不正確(不存在)
  2. 密碼錯誤
  3. 賬戶被鎖定
  4. 密碼過期

在實際專案中為了安全起見,賬戶不正確和密碼錯誤統一返回“使用者名稱或密碼不正確”類似的的提示,避免造成賬戶洩露。

下面針對這種情況給予演示

用例程式碼

/**
 * @author 賴柄灃 bingfengdev@aliyun.com
 * @version 1.0
 * @date 2020/10/4 11:20
 */
public class AuthcTest {
    private CurrentSystemAuthenticator authenticator;
    @Before
    public void init() {
        this.authenticator = new CurrentSystemAuthenticator();
    }

    @Test
    public void testAuthc(){
        this.authenticator.authenticate("xiangbei","13");
    }
}

輸出

使用者名稱或密碼不正確
xiangbei 認證未通過!

寫在最後

這一篇文章主要是帶領大家瞭解一下如何通過自定義Realm物件完成shiro認證資料來源的切換。對於MySQL的整合,我們將在後面的文章當中整合SpringBoot時介紹。

下一篇文章將簡單介紹shiro中的密碼加密以及如何配置使用。

本文所涉及的程式碼下載地址:https://github.com/code81192/art-demo/tree/master/shiro-authc-mysql

相關文章