3

我有一个实现了 spring 安全性的 spring MVC 3.0 应用程序。我正在创建一个小弹出窗口来更改当前登录用户的密码。一切都很好,直到我将表单发布到以下操作。

@RequestMapping(value = "principalchangepassword" , method = RequestMethod.POST)
public @ResponseBody String principalchangepassword(Model uiModel, HttpServletRequest httpServletRequest){
    Principal principal = (Principal) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    StandardStringDigester digester = new StandardStringDigester();
    digester.setAlgorithm("SHA-256");   // optionally set the algorithm
    digester.setStringOutputType("hexadecimal");
    digester.setSaltSizeBytes(0);
    digester.setIterations(1);
    String digest = digester.digest(httpServletRequest.getParameter("password1")); 
    principal.setPassword(digest.toLowerCase());
    principal.merge();
    return "Password Updated successfully";
}

当我执行 ajax 调用以更新当前主体的密码时,我收到以下异常消息。

org.hibernate.TransientObjectException: object references an unsaved transient instance – save the transient instance before flushing

我究竟做错了什么 ?

4

3 回答 3

4

我正在使用 BCryptPasswordEncoder 使用弹簧安全性。现在更改密码我所做的是将用户提供的现有密码与数据库值进行比较。

BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
String existingPassword = ... // Password entered by user
String dbPassword       = ... // Load hashed DB password

if (passwordEncoder.matches(existingPassword, dbPassword)) {
    // Encode new password and store it
} else {
    // Report error 
}
于 2017-04-06T19:09:23.900 回答
3

好的,所以我很喜欢使用我从声明中得到的委托人

(Principal) SecurityContextHolder.getContext().getAuthentication().getPrincipal(); 

我需要首先使用 ID 明确地从数据库中获取本金,进行更改然后合并。这是完美运行的最终操作。

@RequestMapping(value = "principalchangepassword" , method = RequestMethod.POST)
public @ResponseBody String principalchangepassword(Model uiModel, HttpServletRequest httpServletRequest){
    Principal principal = (Principal) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
    Principal me = Principal.findPrincipal(principal.getId());
    me.setPassword(httpServletRequest.getParameter("password1"));
    StandardStringDigester digester = new StandardStringDigester();
    digester.setAlgorithm("SHA-256");   // optionally set the algorithm
    digester.setStringOutputType("hexadecimal");
    digester.setSaltSizeBytes(0);
    digester.setIterations(1);
    String digest = digester.digest(me.getPassword());
    me.setPassword(digest.toLowerCase());
    me.merge();
    return "Password Updated successfully";
}

希望它可以帮助那里的人。

于 2012-07-17T15:59:31.527 回答
1

我发现这个问题是因为我正在寻找一种方法来创建一个新用户并设置一个编码密码。Binaryrespawn 的回答已经相当不错了,我只是想为这个问题添加第二个观点。

因此,为了更改密码或创建新用户,实际上并不需要与 Spring 交互。除了确保您已通过身份验证(以及创建您拥有权限的新用户)之外。

最重要的部分是,PasswordEncoder 与 spring 中配置的相匹配,而 AuthenticationProvider 将用于将存储的密码与用户输入的密码进行比较。

更新密码的步骤基本上是:

  1. 从数据库加载现有用户(通过idusername)。
  2. 获取 spring 用来进行身份验证的 PasswordEncoder。
  3. 存储用户。

创建新用户的步骤基本上是:

  1. 从前端检索用户对象。
  2. 获取 Spring 用来进行身份验证的 PasswordEncoder
  3. 将用户发送的密码替换为编码版本并将其放回用户对象中。
  4. 存储用户。

这是一个定义 REST 端点以创建新用户的示例:

private BCryptPasswordEncoder passwordEncoder = new BCryptPasswordEncoder();

@POST
@Path("user/create")
@Produces(MediaType.APPLICATION_JSON)
@Secured("ROLE_ADMIN")
public User createUser(User user) {
    if(user.getPassword() == null || user.getPassword().equals("")) {
        //throw exception...
    }
    user.setPassword(passwordEncoder.encode(user.getPassword()));
    userService.save(user);
    return user;
}
于 2014-02-28T11:47:55.613 回答