2012-10-15 40 views
0

這是我第二次在項目中使用apache shiro,但第一次是salting密碼。這是我使用apache shiro 1.2.0的時間。我在使用jsp,spring,JPA(spring-data-jpa)的web應用程序中使用shiro,並在保存到數據庫之前使用SHA256進行加密,然後使用base64。我有一個SaltedJPARealm,一個Sha256CredentialMatcher它實現了一個HashedCredentialMatcher。這就是我要做的麻煩apache shiro saltedauthentication.hashProvidedCredentials沒有給出預期的散列

在我的控制器創建用戶

RandomNumberGenerator rng = new SecureRandomNumberGenerator(); 
ByteSource salt = rng.nextBytes(10);    
     String hashedPasswordBase64 = new Sha256Hash(signupForm.getPassword(),salt).toBase64(); 

userService.createUser(signupForm.getFullName(), signupForm.getEmail(), hashedPasswordBase64, salt.toBase64()); 

所以應該我的密碼是password1234和生成的鹽是​​所以在我的數據庫,我有密碼:whb+0AihIGJ4n8QwULj1tR6qSwCrA+1BUvnoe4q4Cy4=鹽在salt field in the database是一樣的。

在我在春天的配置是:

<!--....--> 
<bean id="saltedJPARealm" class="bla.bla.webapp.security.SaltedJPARealm"> 
    <constructor-arg ref="credMatcher"/> 
</bean> 

    <bean id="credMatcher" class="bla.bla.webapp.security.Sha256CredentialMatcher"> 
     <property name="storedCredentialsHexEncoded" value="false" /> 
     <property name="hashAlgorithmName" value="SHA-256" /> 
     <!--<property name="hashIterations" value="1024" />--> 
    </bean> 
<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager" depends-on="userRepository"> 
    <property name="realm" ref="saltedJPARealm" /> 
</bean> 
<!--....--> 

登錄用戶

Subject currentUser = SecurityUtils.getSubject(); 
if (!currentUser.isAuthenticated()) { 
      UsernamePasswordToken token = new UsernamePasswordToken(loginForm.getEmail(), loginForm.getPassword(), loginForm.isRememberMe()); 
    SecurityUtils.getSubject().login(token); 
     } 

SaltedJPARealm's doGetAuthenticationInfo(AuthenticationToken at)回報SaltedAuthenticationInfo從數據庫中獲取用戶後:

ByteSource salt = ByteSource.Util.bytes(user.getSalt());   
return new SimpleAuthenticationInfo(user, user.getPassword().toCharArray(),salt,this.getName()); 

的Sha256CredentialMatcher的32051106540​​樣子:

Object tokenfromSubmition = hashProvidedCredentials(token.getCredentials(),((SaltedAuthenticationInfo)info).getCredentialsSalt(),0); 
    Object passwordFromStorage =this.getCredentials(info); 

    Boolean match = equals(tokenfromSubmition, passwordFromStorage); 
    return match; 

完整的代碼可here on pastie認證失敗與此有關。但是當我更改密碼時不要使用密碼(創建帳戶時)並返回AuthenticationInfo而不是SaltedAuthenticationInfo。它適用於同一班級。我在想,究竟做錯了什麼?

+0

是否有你沒有使用PasswordMatcher和PasswordService的原因?這些自動使用安全隨機生成的鹽,並直接進行密碼比較。 –

+0

'passwordService'使用默認的'sha-256'加密和50,000次迭代(我認爲是這樣),我還沒有找到任何方法來改變這些默認值。在嘗試時,在生成密碼時調試過程中似乎很慢。所以我回落到自定義實現。謝謝 –

+0

我在下面回答了有關'passwordService'用法的問題。我知道它沒有解決你最初發布的問題,但我認爲你會發現使用起來更容易/更好。 –

回答

1

PasswordService是一個POJO(具有嵌套屬性)和它的嵌套屬性可與彈簧被配置一樣好:

<bean id="passwordService" class="org.apache.shiro.authc.credential.DefaultPasswordService"> 
    <property name="hashService.hashAlgorithmName" value="SHA-512"/> 
    <property name="hashService.hashIterations" value="500000"/> 
</bean> 

<bean id="myRealm" class="..."> 
    <property name="credentialsMatcher"> 
    <bean class="org.apache.shiro.authc.credential.PasswordMatcher"> 
     <property name="passwordService" ref="passwordService"/> 
    </bean> 
    </property> 
</bean> 

這允許myRealm實例期間一個用於憑證檢查的PasswordService登錄嘗試。

要使用PasswordService對密碼進行加密,當終端用戶自己的密碼(即賬戶註冊或密碼重置時),你可以注入PasswordService bean,然後使用它:

String encryptedPassword = passwordService.encryptPassword(signupForm.getPassword()); 

userService.createUser(signupForm.getFullName(), signupForm.getEmail(), encryptedPassword); 

我想你會發現Spring的配置和代碼使用比低級別的隨機數生成器和HashService + Hash API更好用。

HTH!

+0

感謝您的回覆。你的建議與Realm一樣嗎? : 'protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken at) // ..... return new SimpleAuthenticationInfo(user,user.getPassword()。toCharArray(),this.getName()); }' –

+0

@blacksensei yep! –

+0

@blacksensei P.S.此方法假定您使用PasswordService首先在數據存儲中設置密碼(如上面的第二個代碼塊所示)。然後可以使用存儲的值在登錄時進行比較。 –