1. 程式人生 > >Shiro -認證憑據(密碼)加密的那些事

Shiro -認證憑據(密碼)加密的那些事

一般來說,實際專案中隱私資料沒有在網路上明文跑路,都會採用不同的加密演算法。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());
	}