'Why validation not work for encoded password

In my project i add some validation for Signup form fields. While click on submit button password validation not check orignal password like @AAAzzz123 but it check encoded password like $2a$10$kUm6AxxH3SNSIoUtP6V7WOlFTIORTOILKDFGOP and produce validation error message. Here down is my code.

Entity

public class User {
    ...
    ...
    ...

    @Pattern(regexp = "(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[^\\da-zA-Z]).{8,15}$")
    private String password;
}

Controller

@RequestMapping(value = "/register", method = RequestMethod.POST)
    public String resiterUser(@Valid @ModelAttribute("user") User user, 
                                  BindingResult result)
    {
        
        if(result.hasErrors())
        {
            return "signup";
        }

        // Problem is here
        user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
        userRepo.save(user);
        return "redirect:/";
}

View

<form th:action="@{/register}" method="post">
    
    <div class="form-outline mb-4">
        <label class="form-label" for="form3Example4cg">Password</label>
        <input type="password" 
            th:classappend="${#fields.hasErrors('password') ? 'is-invalid' : ''}" 
            class="form-control form-control-lg"
            name="password" />
        <div id="validation" class="text-danger" th:each="e: ${#fields.errors('password')}" th:text=${e}>

        </div>
    </div>
    
    <div class="d-flex">
        <button type="submit" class="btn bg-primary">Submit</button>
    </div>
    
</form>


Solution 1:[1]

I solved my problem by the help of @OrangeDog, Who give me the way how to solve this problem.

  • Declare another variable dummyPassword with transient keyword which is temporary variable.
  • Here i am trying to validate the user entered password in Controller, If regular expression is match so, dummyPassword into encoded password and save into database otherwise got validation error

Entity:

public class User {
    ...
    ...
    ...

    private String password;

    @Pattern(regexp = "(?=.*[a-z])(?=.*[A-Z])(?=.*\\d)(?=.*[^\\da-zA-Z]).{8,15}$")
    private transient String dummyPassword;
}

In Controller set dummyPassword in orignal password

user.setPassword(bCryptPasswordEncoder.encode(user.getDummyPassword()));

Thymeleaf

<div class="form-outline mb-4">
    <label class="form-label" for="form3Example4cg">Password</label>
    <input type="password" 
        id="form3Example4cg"
        th:classappend="${#fields.hasErrors('newPassword') ? 'is-invalid' : ''}"
        class="form-control form-control-lg"
        name="newPassword" />
    <div class="text-danger" th:each="e: ${#fields.errors('newPassword')}" th:text=${e}>

    </div>
</div>

Solution 2:[2]

There are two phases of validation - the MVC layer and the JPA layer. If you use the same model class for both layers then you can't use the same field for two different things.

You can separate them like this, for example:

@Entity
@Table(name = "USER")
public class User {

    @Column(name = "password")
    @Pattern(regexp = "^\\$2[aby]\\$.{56}$")
    private String encodedPassword

    // for form binding only
    private transient String newPassword;

}
user.setEncodedPassword(bCryptPasswordEncoder.encode(user.getNewPassword()));

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2