【问题标题】:Authentication in Spring Security whith encoded password使用编码密码在 Spring Security 中进行身份验证
【发布时间】:2012-03-07 02:59:40
【问题描述】:

拥有带有密码编码的简单 Spring Security webapp:

<security:authentication-manager alias="authenticationManager">
<security:authentication-provider user-service-ref="personService">
     <security:password-encoder hash="md5" ref="passwordEncoder"> 
        <!--  <security:salt-source user-property="username"/> -->
     </security:password-encoder>
 </security:authentication-provider>
</security:authentication-manager>

编码也很简单:

 person.setPassword(encoder.encodePassword(person.getPassword(), null));

所以在数据库中所有的密码都会被编码。 现在我想在应用程序中对具有特定用户名的某些用户进行身份验证。 之前(当密码是明文时)是这样的:

UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(
                username, password);
Authentication authentication = authenticationManager.authenticate(token);
SecurityContextHolder.getContext().setAuthentication(authentication);

但现在我从 DB 获得编码密码,无法像以前那样进行身份验证。

问题。 Spring 不知道密码来自已经编码的 UsernamePasswordAuthenticationToken。他正在第二次对其进行编码。 谁能帮忙?

编辑

所以我在这里看到了两种解决方案:

  1. 实现自定义 DaoAuthenticationProvider 添加检查两个密码是否已经散列
  2. 实现自定义身份验证并将其手动放入安全上下文中。

还有其他人吗?什么是最好的?

【问题讨论】:

  • 包含detail here 中的一些 SpringSecurity,可能对某些人有用。

标签: spring authentication spring-security md5


【解决方案1】:

您实际上并没有说出了什么问题,但身份验证代码应该与非哈希版本完全相同。

如果您在数据库中有哈希密码,并且将相应的编码器注入到身份验证提供程序中,则用户提供的密码将在与数据库版本进行比较之前由编码器进行哈希处理。

确保:

  1. 创建UsernamePasswordAuthenticationToken 时使用未散列的密码值
  2. 数据库中的值确实与编码器产生的哈希值相同。自己加载并在测试中检查。例如,数据库可能会以大写形式存储它。

此外,您可能应该选择比普通 MD5 更好的东西。例如,您可能想查看 bcrypt,它在 Spring Security 3.1 中受支持并自动使用随机盐值。

更新

您关于创建接受散列密码的提供程序的建议不是一个好的建议。这将允许窃取密码哈希的任何人直接使用它进行身份验证(从而首先破坏了哈希的目的)。

只需验证您的电子邮件 URL 链接,加载该用户的信息并为他们创建一个 Authentication 对象:

UserDetails user = ... // load user here
Authentication a = new UsernamePasswordAuthenticationToken(user, null, user.getAuthorities());
SecurityContextHolder.getContext().setAuthentication(a);

【讨论】:

  • 问题出在 1. 创建 UsernamePasswordAuthenticationToken 时,当我从 DB 加载 UserDetails 对象时,我只有密码的散列版本(在我的情况下 - 通过确认键)
  • 使用存储的密码不会对用户进行身份验证(我认为这是您想要做的)。如果没有,您需要澄清您要达到的目标。使用您事先知道正确的密码调用身份验证管理器没有多大意义。
  • 我正在尝试验证用户,该用户单击了注册电子邮件中的链接。所以 UserDetails 对象来自数据库的确认键来自电子邮件中的确认链接。
  • 那么检查密码就没有意义了。在链接中使用短暂的随机 URL,验证密钥并直接设置安全上下文。
  • 太好了,只剩下一个问题了(:如何直接设置安全上下文?
猜你喜欢
  • 2011-12-01
  • 2014-11-09
  • 2011-05-26
  • 2017-10-16
  • 2016-08-27
  • 2012-11-27
  • 2021-04-29
  • 2020-02-28
相关资源
最近更新 更多