15

我已经使用 spring security 实现了更改密码功能,但是 ((UserDetails) principal).getPassword()) 为登录用户返回 null。

如果我没记错的话,这曾经在 3.0 的早期版本中起作用。这在 3.1 中是否已更改,因此无法检索登录用户的当前密码?

在下面的代码中,我正在检查从网页输入的用户密码的当前密码。然后我正在检查登录用户的密码是否与输入的密码匹配。如果是这样,那么我想设置 oldPasswordMatchNewPassword = true。

如何实现此功能?

@RequestMapping(value = "/account/changePassword.do", method = RequestMethod.POST)
    public String submitChangePasswordPage(
            @RequestParam("oldpassword") String oldPassword,
            @RequestParam("password") String newPassword) {
        Object principal = SecurityContextHolder.getContext()
                .getAuthentication().getPrincipal();
        String username = principal.toString();
        if (principal instanceof UserDetails) {
            username = ((UserDetails) principal).getUsername();
            System.out.println("username: " + username);
            System.out.println("password: "
                    + ((UserDetails) principal).getPassword());
            if (((UserDetails) principal).getPassword() != null) {
                if (((UserDetails) principal).getPassword().equals(oldPassword)) {
                    oldPasswordMatchNewPassword = true;
                }
            }
        }
    if (oldPasswordMatchNewPassword == true) {
        logger.info("Old password matches new password. Password will be updated.");
        changePasswordDao.changePassword(username, newPassword);
        SecurityContextHolder.clearContext();
        return "redirect:home.do";
    } else {
        logger.info("Old password did not match new password. Password will be not be updated.");
        return null;
    }
}

我放了几个 sysout() 以便我可以看到返回的值。对于 ((UserDetails) principal).getUsername() 我可以看到正确的登录用户。((UserDetails) principal).getPassword() 它返回 null。

如何获得 ((UserDetails) principal).getPassword() 这个值?

提前致谢!

4

3 回答 3

26

我使用这段代码(erase-credentials="false")来解决这个问题。我不知道这是否是一个优雅的解决方案,但它解决了我的问题:

<authentication-manager alias="authenticationManager" erase-credentials="false">
    <!-- authentication-provider user-service-ref="userService" -->
    <authentication-provider>
        <jdbc-user-service data-source-ref="dataSource" />
    </authentication-provider>
</authentication-manager>
于 2013-01-13T21:53:33.007 回答
6

是的,这在 3.1 版中已更改。默认情况下,身份验证成功后会清除凭据。您可以将其设置eraseCredentialsAfterAuthentication为 falseProviderManager以防止这种情况发生。在此处查看详细信息:http: //static.springsource.org/spring-security/site/docs/3.2.x/reference/core-services.html#core-services-erasing-credentials

于 2013-01-13T12:24:14.363 回答
2

由于用户通过身份验证后密码不会保留在内存中(通常是一件好事),因此您需要显式重新加载它才能使用它。另一种更灵活的策略是注入一个实例AuthenticationManager并直接使用它:

String name = SecurityContextHolder.getContext().getAuthentication();

try {
    authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(name, oldPassword));
    // Update password here with your dao
} catch (AuthenticationException e) {
    // Old password was wrong
}

这样您就不必担心密码编码策略之类的事情。请注意,您不应该以纯文本形式存储密码。它们应该使用bcrypt 或类似的东西进行散列。

于 2013-01-13T22:30:57.977 回答