簡體   English   中英

用於基本身份驗證的Apache Shiro憑據匹配始終失敗

[英]Apache Shiro credentials matching for basic authentication always fails

我正在嘗試使用Apache Shiro實現基本身份驗證。 我將偵聽器和過濾器添加到了我的web.xml文件中:

<listener>
 <listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
<filter>
 <filter-name>ShiroFilter</filter-name>
 <filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
 <filter-name>ShiroFilter</filter-name>
 <url-pattern>/*</url-pattern>
 <dispatcher>REQUEST</dispatcher>
 <dispatcher>FORWARD</dispatcher>
 <dispatcher>INCLUDE</dispatcher>
 <dispatcher>ERROR</dispatcher>
</filter-mapping>

並將authcBasic過濾器應用於我的shiro.ini文件中的受保護頁面:

[urls]
/api/users = anon
/login.html = anon
/** = authcBasic

另外,我使用Sha256CredentialsMatcher和JdbcRealm子類作為領域:

[main]
jdbcRealm = my.package.SaltColumnJDBCRealm
sha256Matcher = org.apache.shiro.authc.credential.Sha256CredentialsMatcher
sha256Matcher.storedCredentialsHexEncoded = false
sha256Matcher.hashIterations = 1024 
jdbcRealm.credentialsMatcher = $sha256Matcher
jdbcRealm.authenticationQuery = SELECT password, salt FROM User WHERE email = ?
builtInCacheManager = org.apache.shiro.cache.MemoryConstrainedCacheManager
securityManager.cacheManager = $builtInCacheManager
securityManager.realms = $jdbcRealm

領域類:

public class SaltColumnJDBCRealm extends org.apache.shiro.realm.jdbc.JdbcRealm
{
    public SaltColumnJDBCRealm()
    {
        this.setSaltStyle(SaltStyle.COLUMN);
    }
}

可以通過將JSON對象發布到RESTful Web服務來將用戶添加到數據庫:

import javax.ejb.EJB;
import javax.enterprise.context.RequestScoped;
import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.WebApplicationException;
import javax.ws.rs.core.MediaType;
import org.apache.shiro.crypto.RandomNumberGenerator;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.util.ByteSource;

@Path("/users")
@RequestScoped
public class UserService
{
    @EJB
    UserDao userDao;

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public void register(User user)
    {
        try
        {
            encryptPassword(user);
            userDao.persist(user);
        }
        catch(InvalidEntityException | UnsupportedEncodingException e)
        {
            throw new WebApplicationException(e);
        }
    }

    private static void encryptPassword(User user) throws UnsupportedEncodingException
    {
        RandomNumberGenerator rng = new SecureRandomNumberGenerator();
        ByteSource salt = rng.nextBytes();

        String hashedPasswordBase64 = new Sha256Hash(user.getPassword(), salt, 1024).toBase64();
        user.setPassword(hashedPasswordBase64);
        user.setSalt(salt.toBase64());
    }
}

(這幾乎是Shiro網頁上教程之后的內容。)

新用戶的此注冊工作正常,並且當客戶端嘗試進行身份驗證時,用戶名和密碼可以毫無問題地到達服務器。 但是登錄總是失敗。

我已經通過調試到以下幾點來跟蹤該問題:Sha256CredentialsMatcher從數據庫中檢索與接收到的用戶名匹配的鹽,並使用此鹽對所接收的密碼進行哈希處理。 然后,它將結果與該用戶名已存儲在數據庫中的密碼哈希進行比較。 就我而言,即使客戶端發送了正確的用戶名和密碼組合,這些哈希也始終不匹配。 在將鹽和/或密碼哈希存儲到數據庫中並再次檢索它們的過程中,鹽和/或密碼哈希似乎已更改。 或好像在哈希相同的密碼時, Sha256Hash(...)構造函數和Sha256CredentialsMatcher.doCredentialsMatch(...)方法以不同的方式達到不同的結果。 但是我不知道這可能如何發生。

我已經嘗試過將鹽作為salt.toString()而不是salt.toBase64()存儲在數據庫中:

public class UserService
{
    ... 
    private static void encryptPassword(User user) throws UnsupportedEncodingException
    {
        ... 
        user.setSalt(salt.toString());
...

兩個變體都會發生錯誤。

我使用以下方法並且有效

credentialsMatcher = org.apache.shiro.authc.credential.HashedCredentialsMatcher
credentialsMatcher.hashAlgorithmName=SHA-256
credentialsMatcher.storedCredentialsHexEncoded = false
credentialsMatcher.hashIterations = 1024
credentialsMatcher.hashSalted = true

在您的實現中缺少credentialsMatcher.**hashSalted = true**部分。

三個月后,我找到了解決方案。 :-/與Shiro文檔中的教程相反,您不能簡單地實例化ByteSource對象並將其用作鹽(至少不能用於1.2.3版)。 相反,您需要從ByteSource對象獲取一個String並將其用作鹽。 我選擇獲取Base64編碼的String,所以我的encryptPassword方法現在如下所示:

private static void encryptPassword(User user) throws UnsupportedEncodingException
{
    RandomNumberGenerator rng = new SecureRandomNumberGenerator();
    ByteSource byteSource = rng.nextBytes();
    String salt = byteSource.toBase64();
    String hashedPasswordBase64 = new Sha256Hash(user.getPassword(), salt, 1024).toBase64();
    user.setPassword(hashedPasswordBase64);
    user.setSalt(salt);
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM