Shiro-密碼的MD5加密


1.密碼的加密

  在數據表中存的密碼不應該是123456,而應該是123456加密之后的字符串,而且還要求這個加密算法是不可逆的,即由加密后的字符串不能反推回來原來的密碼,如果能反推回來那這個加密是沒有意義的。

  著名的加密算法,比如 MD5,SHA1

2.MD5加密

  1). 如何把一個字符串加密為MD5

  2). 使用MD5加密算法后,前台用戶輸入的字符串如何使用MD5加密,需要做的是將當前的Realm 的credentialsMatcher屬性,替換為Md5CredentialsMatcher 由於Md5CredentialsMatcher已經過期了,推薦使用HashedCredentialsMatcher 並設置加密算法即可。

/**
 * {@code HashedCredentialsMatcher} implementation that expects the stored {@code AuthenticationInfo} credentials to be
 * MD5 hashed.
 * <p/>
 * <b>Note:</b> <a href="http://en.wikipedia.org/wiki/MD5">MD5</a> and
 * <a href="http://en.wikipedia.org/wiki/SHA_hash_functions">SHA-1</a> algorithms are now known to be vulnerable to
 * compromise and/or collisions (read the linked pages for more).  While most applications are ok with either of these
 * two, if your application mandates high security, use the SHA-256 (or higher) hashing algorithms and their
 * supporting <code>CredentialsMatcher</code> implementations.</p>
 *
 * @since 0.9
 * @deprecated since 1.1 - use the HashedCredentialsMatcher directly and set its
 *             {@link HashedCredentialsMatcher#setHashAlgorithmName(String) hashAlgorithmName} property.
 */
public class Md5CredentialsMatcher extends HashedCredentialsMatcher {

    public Md5CredentialsMatcher() {
        super();
        setHashAlgorithmName(Md5Hash.ALGORITHM_NAME);
    }
}

 

3.使用MD5加密

  1). 修改配置文件的Realm 的默認的credentialsMetcher 為

<bean id="jdbcRealm" class="com.java.shiro.realms.ShiroRealm">
        <property name="credentialsMatcher">
            <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher">
                <property name="hashAlgorithmName" value="MD5"></property> <!-- 加密算法的名稱 -->
                <property name="hashIterations" value="1024"></property> <!-- 配置加密的次數 -->
            </bean>
        </property>
    </bean>

 

   2). 通過斷點可以看到,實際的加密為

  

  3). 通過 new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations); 我們可以得到"123456"經過MD5 加密1024后的字符串;

public static void main(String[] args) {
        String hashAlgorithmName = "MD5";
        String credentials = "123456";
        int hashIterations = 1024;
        Object obj = new SimpleHash(hashAlgorithmName, credentials, null, hashIterations);
        System.out.println(obj);
    }

 

  將realm中的 明文123456改為fc1709d0a95a6be30bc5926fdb7f22f4

在進行登錄測試。

登錄成功。

 

4. 以上的加密還存在問題,如果兩個人的密碼一樣,即存在數據表里中的兩個加密后的字符串一樣,然而我們希望即使兩個人的密碼一樣,加密后的兩個字符串也不一樣。即需要用到MD5鹽值加密。

  1).修改Realm使用鹽值加密 完整的ShiroRealm.java

  

public class ShiroRealm extends AuthenticatingRealm {

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(
            AuthenticationToken token) throws AuthenticationException {
        System.out.println("doGetAuthenticationInfo " + token);

        // 1. 把AuthenticationToken 轉換為UsernamePasswordToken
        UsernamePasswordToken up = (UsernamePasswordToken) token;
        // 2. 從UsernamePasswordToken 中來獲取username
        String username = up.getUsername();
        // 3. 調用數據庫的方法,從數據庫中查詢username對應的用戶記錄
        System.out.println("從數據庫中獲取userName :" + username + " 所對應的用戶信息.");
        // 4. 若用戶不存在,則可以拋出 UnknownAccoountException 異常
        if ("unknown".equals(username)) {
            throw new UnknownAccountException("用戶不存在");
        }
        // 5. 根據用戶信息的情況,決定是否需要拋出其他的AuthencationException 異常 假設用戶被鎖定
        if ("monster".equals(username)) {
            throw new LockedAccountException("用戶被鎖定");
        }
        // 6. 根據用戶的情況,來構建AuthenticationInfo 對象並返回,通常使用的是
        // SimpleAuthenticationInfo
        // 以下信息是從數據庫獲取的.

        Object principal = username; // principal 認證的實體信息.
                                        // 可以是username,也可以是數據表對應的用戶的實體類對象
//        String credentials = "fc1709d0a95a6be30bc5926fdb7f22f4"; // credentials:密碼
        String credentials = null; // credentials:密碼
        String realmName = getName();
        AuthenticationInfo info = null;/*new SimpleAuthenticationInfo(principal, credentials, realmName);*/
        
        if("admin".equals(username)){
            credentials = "038bdaf98f2037b31f1e75b5b4c9b26e"; 
        }else if("user".equals(username)){
            credentials = "098d2c478e9c11555ce2823231e02ec1"; 
        }
        
        ByteSource credentialsSalt = ByteSource.Util.bytes(username);//這里的參數要給個唯一的;
 info = new SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName); return info;
    }
    
}

 

  上邊的密碼我們可用mian方法得到

public static void main(String[] args) {
        String hashAlgorithmName = "MD5";
        String credentials = "123456";
        int hashIterations = 1024;
        ByteSource credentialsSalt = ByteSource.Util.bytes("user");
        Object obj = new SimpleHash(hashAlgorithmName, credentials, credentialsSalt, hashIterations);
        System.out.println(obj);
    }

 

經過測試,登錄成功。

  2). 筆記

  • 1. 為什么使用 MD5 鹽值加密:
    •   希望即使兩個原始密碼相同,加密得到的兩個字符串也不同。
  • 2. 如何做到:
    •   1). 在 doGetAuthenticationInfo 方法返回值創建 SimpleAuthenticationInfo 對象的時候, 需要使用SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName) 構造器
    •   2). 使用 ByteSource.Util.bytes() 來計算鹽值.
    •   3). 鹽值需要唯一: 一般使用隨機字符串或 user id
    •   4). 使用 new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations); 來計算鹽值加密后的密碼的值.

 


免責聲明!

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



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