如何使用 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】:

似乎文档将UserUserDAO 称为您自己的用户模型实体(表)和用户数据访问层实体(保存、更新、删除和检索的类)。这些不一定是 Apache Shiro 的一部分(因为某些数据访问层可能在 RDBMS 中,一些在内存数据库中,有些甚至可能在属性文件中,为什么不呢?)

您必须实现UserUserDAO 才能保存到您自己的持久性存储中。

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 将散列密码存储到数据库中?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Laravel 5.8 将散列密码存储到数据库中

SQL Server - 如何将散列密码插入表?

如何使 Vue.js 将散列密码发布到 Django REST API AbstractBaseUser 自定义模型?

Shiro - 无法使用散列密码进行身份验证

使用 bcryptjs 将散列密码保存到数据库时出错

PHP 去散列密码