shiro系列五、shiro密碼MD5加密
阿新 • • 發佈:2018-12-12
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); 來計算鹽值加密後的密碼的值.