【发布时间】:2015-09-07 19:05:18
【问题描述】:
我正在尝试使用 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 网络服务来将用户添加到数据库中:
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());
}
}
(这几乎是在tutorial from the Shiro web page之后。)
这种新用户注册工作正常,当客户端尝试进行身份验证时,用户名和密码可以毫无问题地到达服务器。但是后来登录总是失败。
我已经通过调试到以下几点来追踪问题:
Sha256CredentialsMatcher 从数据库中检索与接收到的用户名匹配的盐,并使用该盐对接收到的密码进行哈希处理。然后,它将结果与已存储在数据库中的该用户名的密码散列进行比较。只是在我的情况下,这些哈希永远不会匹配,即使客户端发送了正确的用户名和密码组合。看起来好像盐和/或密码哈希在将它们存储在数据库中并再次检索它们的过程中发生了变化。或者好像Sha256Hash(...) 构造函数和Sha256CredentialsMatcher.doCredentialsMatch(...) 方法在散列相同密码时会得出不同的结果。但我不知道这会如何发生。
我已经尝试在数据库中将盐存储为salt.toString() 而不是salt.toBase64():
public class UserService
{
...
private static void encryptPassword(User user) throws UnsupportedEncodingException
{
...
user.setSalt(salt.toString());
...
两种变体都会出现错误。
【问题讨论】:
标签: java authentication shiro