shiro學習之HashedCredentialsMatcher密碼匹配過程

1.加密
用戶註冊時,系統爲輸入的密碼進行加密,此處使用MD5算法,“密碼+鹽(用戶名+隨機數)”的方式生成散列值:


public class passwordEncry{

    ``````````````````````````````````````
    ```````````````````````````````````````
    //隨機數生成器
    private static RandomNumberGenerator randomNumberGenerator = new SecureRandomNumberGenerator();

    //指定散列算法爲md5
    private String algorithmName = "MD5";
    //散列迭代次數
    private final int hashIterations = 2;

    /**
     * 生成隨機鹽值對密碼進行加密
     * @param userLogin  登錄識別串(用戶名)
     * @return
     */
    public UserLogin encrypt(UserLogin userLogin) {
        userLogin.setSalt(randomNumberGenerator.nextBytes().
        toHex());
        String newPassword = 
        new SimpleHash(algorithmName,userLogin.getPassword(),
            ByteSource.Util.bytes(userLogin.getCredentialsSalt())           ,hashIterations).toHex();

        userLogin.setPassword(newPassword);
        return userLogin;

        ``````````````````````
    }
    }

這裏的userLogin.getCredentialsSalt()爲加密鹽,我這裏的鹽設爲(登錄識別串+隨機數),生成一個新的加密密碼,並把新密碼覆蓋原明文密碼存到數據庫。加密完成。

2.HashedCredentialsMatcher的配置

<bean id="credentialsMatcher"
        class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
        <property name="hashAlgorithmName" value="MD5" />
        <property name="hashIterations" value="2" />
        <property name="storedCredentialsHexEncoded" value="true" />
    </bean>

HashedCredentialsMatcher配置的屬性值要跟加密時的屬性(hashAlgorithmName,hashIterations,storedCredentialsHexEncoded)一致,storedCredentialsHexEnc表示是否存儲散列後的密碼爲16進制,需要和生成密碼時的一樣。

3.得到Token
從客戶輸入獲取token(令牌)

   @Override
    protected AuthenticationToken createToken(ServletRequest request,ServletResponse response) {
        String username = request.getParameter("loginString");
        String password = request.getParameter("pwd");
        String rememberMe = request.getParameter("rememberMe");
        String host = getHost(request);
        UsernamePasswordToken token = 
                new UsernamePasswordToken(username, 
                password, 
                Boolean.parseBoolean(rememberMe), host);

                return token;
    }

4.Realm認證
自己實現一個Realm,重寫doGetAuthenticationInfo,得到一個AuthenticationInfo對象。

 @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        String username = (String)token.getPrincipal();

        UserLogin userLogin = userService.getUserLogin(username);

        if (userLogin == null) {
            throw new UnknownAccountException("用戶不存在");
        }

        if("S".equals(userLogin.getStatus())) {
            throw new LockedAccountException("無效賬號");
        }

        SimpleAuthenticationInfo authenticationInfo = 
        new SimpleAuthenticationInfo(
            userLogin, //登錄識別串信息
            userLogin.getPassword(), //密碼
           ByteSource.Util.bytes(userLogin.getCredentialsSalt()),//鹽值
                getName()  //realm name
        );
        return authenticationInfo;
    }

5.密碼的匹配
最終會來到HashedCredentialsMatcher類的doCredentialsMatch()方法進行密碼的比對,此方法包含兩個參數AuthenticationToken token, AuthenticationInfo info,思路一下子豁然開朗。

  @Override
    public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) { 

        Object tokenHashedCredentials = 
        hashProvidedCredentials(token, info);  

        Object accountCredentials = getCredentials(info); 

       return equals(tokenHashedCredentials, accountCredentials);
    } 

方法的最後通過一個equals函數進行散列的比較:

           //equals()方法的主要代碼:
            byte[] tokenBytes = toBytes(tokenCredentials);
            byte[] accountBytes = toBytes(accountCredentials);
            return Arrays.equals(tokenBytes, accountBytes);

驗證完畢,最後執行subject.login(token)登錄成功。

此處只簡單介紹了shiro一種匹配器HashedCredentialsMatcher的認證過程,除了這個匹配器還有另外的匹配器,如PasswordMatcher(密碼匹配器),道理都差不多。

本人初學shiro,理解上有不妥之處還請大家指出批評!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章