New Password Storage In Spring Security 5 – Spring Security 5中的新密码存储

最后修改: 2018年 4月 6日

1. Introduction


With the latest Spring Security release, a lot has changed. One of those changes is how we can handle password encoding in our applications.

随着最新的Spring Security发布,很多东西都发生了变化。其中一个变化是我们如何在应用程序中处理密码编码。

In this tutorial, we’re going to explore some of these changes.


Later, we’ll see how to configure the new delegation mechanism and how to update our existing password encoding, without our users recognizing it.


2. Relevant Changes in Spring Security 5.x

2.Spring Security 5.x的相关变化

The Spring Security team declared the PasswordEncoder in as deprecated. It was a logical move, as the old interface wasn’t designed for a randomly generated salt. Consequently, version 5 removed this interface.

Spring Security团队宣布中的PasswordEncoder已经废弃。这是一个合乎逻辑的举动,因为旧的接口并不是为随机生成的盐而设计的。因此,版本5删除了这个接口。

Additionally, Spring Security changes the way it handles encoded passwords. In previous versions, each application employed one password encoding algorithm only.

此外,Spring Security改变了它处理编码密码的方式。在以前的版本中,每个应用程序只采用一种密码编码算法。

By default, StandardPasswordEncoder dealt with that. It used SHA-256 for the encoding. By changing the password encoder, we could switch to another algorithm. But our application had to stick to exactly one algorithm.


Version 5.0 introduces the concept of password encoding delegation. Now, we can use different encodings for different passwords. Spring recognizes the algorithm by an identifier prefixing the encoded password.


Here’s an example of a bcrypt encoded password:



Note how bcrypt is specified in curly braces in the very beginning.


3. Delegation Configuration


If the password hash has no prefix, the delegation process uses a default encoder. Hence, by default, we get the StandardPasswordEncoder.


That makes it compatible with the default configuration of previous Spring Security versions.

这使得它与以前的Spring Security版本的默认配置兼容。

With version 5, Spring Security introduces PasswordEncoderFactories.createDelegatingPasswordEncoder(). This factory method returns a configured instance of DelegationPasswordEncoder.

在版本5中,Spring Security引入了PasswordEncoderFactories.createDelegatingPasswordEncoder().该工厂方法返回DelegationPasswordEncoder的一个配置实例。

For passwords without a prefix, that instance ensures the just mentioned default behavior. And for password hashes that contain a prefix, the delegation is done accordingly.


The Spring Security team lists the supported algorithms in the latest version of the corresponding JavaDoc.

Spring 安全团队在最新版本的相应的 JavaDoc中列出了支持的算法。

Of course, Spring lets us configure this behavior.


Let’s assume we want to support:


  • bcrypt as our new default
  • scrypt as an alternative
  • SHA-256 as the currently used algorithm.

The configuration for this set-up will look like this:


public PasswordEncoder delegatingPasswordEncoder() {
    PasswordEncoder defaultEncoder = new StandardPasswordEncoder();
    Map<String, PasswordEncoder> encoders = new HashMap<>();
    encoders.put("bcrypt", new BCryptPasswordEncoder());
    encoders.put("scrypt", new SCryptPasswordEncoder());

    DelegatingPasswordEncoder passworEncoder = new DelegatingPasswordEncoder(
      "bcrypt", encoders);

    return passworEncoder;

4. Migrating the Password Encoding Algorithm


In the previous section, we explored how to configure password encoding according to our needs. Therefore, now we’ll work on how to switch an already encoded password to a new algorithm.


Let’s imagine we want to change the encoding from SHA-256 to bcrypt, however, we don’t want our user to change their passwords.


One possible solution is to use the login request. At this point, we can access the credentials in plain text. That is the moment we can take the current password and re-encode it.


Consequently, we can use Spring’s AuthenticationSuccessEvent for that. This event fires after a user successfully logged into our application.


Here is the example code:


public ApplicationListener<AuthenticationSuccessEvent>
  authenticationSuccessListener( PasswordEncoder encoder) {
    return (AuthenticationSuccessEvent event) -> {
        Authentication auth = event.getAuthentication();

        if (auth instanceof UsernamePasswordAuthenticationToken
          && auth.getCredentials() != null) {

            CharSequence clearTextPass = (CharSequence) auth.getCredentials();
            String newPasswordHash = encoder.encode(clearTextPass);

            // [...] Update user's password

            ((UsernamePasswordAuthenticationToken) auth).eraseCredentials();

In the previous snippet:


  • We retrieved the user password in clear text from the provided authentication details
  • Created a new password hash with the new algorithm
  • Removed the clear text password from the authentication token

By default, extracting the password in clear text wouldn’t be possible because Spring Security deletes it as soon as possible.

默认情况下,提取明文密码是不可能的,因为Spring Security会尽快将其删除。

Hence, we need to configure Spring so that it keeps the cleartext version of the password.


Additionally, we need to register our encoding delegation:


public class PasswordStorageWebSecurityConfigurer {

    public AuthenticationManager authManager(HttpSecurity http) throws Exception {
        AuthenticationManagerBuilder authenticationManagerBuilder = 

   // ...

5. Conclusion


In this quick article, we talked about some new password encoding features available in 5.x.


We also saw how to configure multiple password encoding algorithms to encode our passwords. Furthermore, we explored a way to change the password encoding, without breaking the existing one.


Lastly, we described how to use Spring events to update encrypted user password transparently, allowing us to seamlessly change our encoding strategy without disclosing that to our users.


Lastly and as always, all code examples are available in our GitHub repository.