如何使用 Apache Shiro 将散列密码存储到数据库中?
Posted
技术标签:
【中文标题】如何使用 Apache Shiro 将散列密码存储到数据库中?【英文标题】:How to store hashed pws into a db with Apache Shiro? 【发布时间】:2014-11-04 20:16:17 【问题描述】:我一直在四处寻找,但没有成功。
我希望对我的用户密码进行散列和加盐并将它们存储到数据库中。问题是,如何存储它们?
我看过这个http://shiro.apache.org/realm.html#Realm-authentication,我找到了类似的答案,但没有意义。
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.crypto.RandomNumberGenerator;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
...
//We'll use a Random Number Generator to generate salts. This
//is much more secure than using a username as a salt or not
//having a salt at all. Shiro makes this easy.
//
//Note that a normal app would reference an attribute rather
//than create a new RNG every time:
RandomNumberGenerator rng = new SecureRandomNumberGenerator();
Object salt = rng.nextBytes();
//Now hash the plain-text password with the random salt and multiple
//iterations and then Base64-encode the value (requires less space than Hex):
String hashedPasswordBase64 = new Sha256Hash(plainTextPassword, salt, 1024).toBase64();
User user = new User(username, hashedPasswordBase64);
//save the salt with the new account. The HashedCredentialsMatcher
//will need it later when handling login attempts:
user.setPasswordSalt(salt);
userDAO.create(user);
据我所见,当前存在用户和“UserDAO”,所有这些示例似乎都使用了较旧的 Shiro 示例。
当我查看我阅读的“PasswordService”javadoc 时
帐户创建或密码重置
Whenever you create a new user account or reset that account's password,
我们必须将最终用户提交的原始/明文密码值转换为 存储起来更安全的字符串格式。你可以通过调用 encryptPassword(Object) 方法来创建更安全的值。例如:
String submittedPlaintextPassword = ...
String encryptedValue = passwordService.encryptPassword(submittedPlaintextPassword);
...
userAccount.setPassword(encryptedValue);
userAccount.save(); //create or update to your data store
Be sure to save this encrypted password in your data store
and never the original/raw submitted password.
但是什么是“userAccount”?
很多时候文档非常模糊。
但是我确实注意到有一个“SubjectDAO”类,但没有 UserDAO 类...
所以是的,我对下一步该怎么做感到困惑,所以如果有人可以帮助我,我将不胜感激!
非常感谢!
【问题讨论】:
【参考方案1】:似乎文档将User
和UserDAO
称为您自己的用户模型实体(表)和用户数据访问层实体(保存、更新、删除和检索的类)。这些不一定是 Apache Shiro 的一部分(因为某些数据访问层可能在 RDBMS 中,一些在内存数据库中,有些甚至可能在属性文件中,为什么不呢?)
您必须实现User
和UserDAO
才能保存到您自己的持久性存储中。
UserAccount
也是您要注册用户帐户时使用的模型对象。就像 Gmail 注册一样。
您必须知道 Apache Shiro 只是一个安全层(身份验证、授权等)。持久性必须由您实现。
强烈建议您查看 Spring Data JPA 和 Spring Security。
【讨论】:
我对持久性不是很熟悉,所以感谢您提供的信息。我认为 shiro 领域可以处理所有事情,而不仅仅是从中读取...我听说 Spring 需要大量学习,但我花了很多时间和 Shiro 在一起。我喜欢它,但文档缺乏很多。我想从某种意义上说,我可以获取生成的密码并使用 SQL 查询将其添加到数据库中,还是应该使用某种持久性 API?这些天似乎坚持不懈是首选,但我对此很陌生,所以我不知道。为什么你比shiro更喜欢春天?谢谢 是的,您可以使用普通的 JDBC 查询来实现持久层,但使用 API 会减少时间。 Spring 生态系统易于学习,可以很好地协同工作。与 Shiro 类似的 Spring Security 是使用最广泛的安全 API。 谢谢,所以我想我会使用常规查询,但也许学习 JPA 会更好。关于持久层的任何建议?您可能是第一个说这很容易的人之一,即使查看 shiro 与 spring 显示很多人都在谈论它是多么困难或“复杂”,但我自己没有看过它。我听说到处都在使用 Spring,所以我不怀疑它很大。 Shiro 看起来很简单,而且有很多东西可以提供,但是设置它肯定需要一些时间(而且仍然需要时间)。感谢您的帮助!【参考方案2】:当您对密码进行哈希处理时:
DefaultPasswordService passwordService = new DefaultPasswordService();
String encytptedPwd= passwordService.encryptPassword("your password");
上面的api会生成包含salt的密码。
使用 JDBC 原生 api 更新此密码...
当你实现 JDBCRealm 时
PasswordMatcher credentialsMatcher = new PasswordMatcher();
this.setCredentialsMatcher(credentialsMatcher);
上面将设置凭据匹配器并使用SimpleAuthenticationInfo
来验证您的登录。
PasswordMatcher 也可以配置为使用 ini 文件。
【讨论】:
谢谢。由于我已经为我的网络应用程序配置了我的 ini 文件,我认为最好保留它。我将如何访问我的 ini 文件数据?另外根据我发现它说这个#privateSalt需要在shiro.ini中进行base64编码,而不是在Java代码中#Salt是使用安全生成器随机生成的##saltGenerator = org.apache.shiro.crypto.SecureRandomNumberGenerator# #hashService.privateSalt = saltGenerator.nextBytes.toBase64 那么有了这个我将如何访问让我们说“saltGenerator”字段?从 ini 内部?以上是关于如何使用 Apache Shiro 将散列密码存储到数据库中?的主要内容,如果未能解决你的问题,请参考以下文章