Shiro -認證憑據(密碼)加密的那些事
阿新 • • 發佈:2018-11-01
一般來說,實際專案中隱私資料沒有在網路上明文跑路,都會採用不同的加密演算法。Shiro中的認證憑據通常也會採用演算法進行加密。
【1】CredentialsMatcher介面
該介面只有一個方法,doCredentialsMatch,就是用來進行密碼比較的!
原始碼如下:
public interface CredentialsMatcher { /** * Returns {@code true} if the provided token credentials match the stored account credentials, * {@code false} otherwise. * * @param token the {@code AuthenticationToken} submitted during the authentication attempt * @param info the {@code AuthenticationInfo} stored in the system. * @return {@code true} if the provided token credentials match the stored account credentials, * {@code false} otherwise. */ boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info); }
其實現類如下:
裡面可以看到我們常用的MD5演算法和SHA-X演算法。
其中Md5CredentialsMatcher 和Sha1CredentialsMatcher 標註已經過時,通常我們會直接在容器中註冊HashedCredentialsMatcher來使用!
如這裡我們註冊HashedCredentialsMatcher並指定演算法為Md5,xml配置如下:
<!-- 自定義Realm --> <bean id="customRealm" class="com.web.maven.shiro.CustomRealm"> <!-- 將憑證匹配器設定到realm中,realm按照憑證匹配器的要求進行雜湊 --> <property name="credentialsMatcher"> <bean class="org.apache.shiro.authc.credential.HashedCredentialsMatcher"> <!-- 加密演算法 --> <property name="hashAlgorithmName" value="MD5"/> <!-- 加密次數 --> <property name="hashIterations" value="1"/> </bean> </property> </bean>
【2】鹽值加密
使用【1】中的配置情況下,如果兩個人的原始密碼一樣,那麼其加密後的密碼也相同,同樣存在風險。
在HashedCredentialsMatcher中有這樣一個方法:
protected Hash hashProvidedCredentials(Object credentials, Object salt, int hashIterations) { String hashAlgorithmName = assertHashAlgorithmName(); return new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations); }
其中new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations)
就是根據提供的原始憑據,加密演算法,鹽值和加密次數進行加密並返回加密後的結果。鹽值是一個唯一字串,這裡你可以使用loginName作為加密鹽值。
步驟如下:
- 在 doGetAuthenticationInfo 方法返回值建立 SimpleAuthenticationInfo 物件的時候, 需要使用
SimpleAuthenticationInfo(principal, credentials, credentialsSalt, realmName)
構造器; - 使用 ByteSource.Util.bytes() 來計算鹽值;
- 鹽值需要唯一, 一般使用隨機字串或 user id;
- 使用 new SimpleHash(hashAlgorithmName, credentials, salt, hashIterations); 來計算鹽值加密後的密碼的值。
如果使用鹽值加密,我們的doGetAuthenticationInfo修改如下:
@Override
protected AuthenticationInfo doGetAuthenticationInfo(
AuthenticationToken authenticationToken) throws AuthenticationException {
UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
//獲取頁面傳來的使用者賬號
String loginName = token.getUsername();
//根據登入賬號從資料庫查詢使用者資訊
SysUser user = sysUserService.getUserByLoginCode(loginName);
System.out.println("從資料庫查詢到的使用者資訊 : "+user);
//一些異常新娘西
if (null == user) {
throw new UnknownAccountException();//沒找到帳號
}
if (user.getStatus()==null||user.getStatus()==0) {
throw new LockedAccountException();//帳號被鎖定
}
//其他異常...
//返回AuthenticationInfo的實現類SimpleAuthenticationInfo
// return new SimpleAuthenticationInfo(user, user.getPassword(), this.getName());
//鹽值加密
ByteSource credentialsSalt = ByteSource.Util.bytes(loginName);
return new SimpleAuthenticationInfo(user, user.getPassword(), credentialsSalt, this.getName());
}