You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Security Core 3.2.4至5.8.6迁移:密码编码问题咨询

Spring Security 3.2.x 到 5.8.x 密码编码迁移解决方案

从Spring Security Core 3.2.4.RELEASE迁移至5.8.6时,原有的ShaPasswordEncoder已被弃用,使用DelegatingPasswordEncoder无法直接适配原有Salt逻辑,且StandardPasswordEncoder也已弃用,以下是对应解决方案:


一、适配原有Salt逻辑的迁移代码

原有代码包含三种密码编码逻辑,需实现兼容Spring Security 5.x的编码逻辑,同时可整合到DelegatingPasswordEncoder中支持多编码格式。

1. 兼容原有编码逻辑的自定义实现

Spring Security 5.x的PasswordEncoder接口默认不直接接收Salt参数,可自定义工具类或实现接口适配原有逻辑:

import org.springframework.security.crypto.codec.Hex;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;

public class LegacyShaPasswordEncoder implements PasswordEncoder {

    private final String algorithm;

    // 对应原有无参数ShaPasswordEncoder(SHA-1)
    public LegacyShaPasswordEncoder() {
        this("SHA");
    }

    // 对应原有ShaPasswordEncoder(256)(SHA-256)
    public LegacyShaPasswordEncoder(int strength) {
        this(strength == 256 ? "SHA-256" : "SHA");
    }

    private LegacyShaPasswordEncoder(String algorithm) {
        this.algorithm = algorithm;
    }

    // 适配原有encodePassword方法:先无Salt编码一次,再用Salt编码一次
    public String encodeTwice(String rawPassword, String salt) {
        String firstEncode = encode(rawPassword, null);
        return encode(firstEncode, salt);
    }

    // 适配原有changeEncodedPassword/encodSH2Password方法:直接用Salt编码
    public String encode(String rawPassword, String salt) {
        try {
            MessageDigest digest = MessageDigest.getInstance(this.algorithm);
            if (salt != null) {
                digest.update(salt.getBytes());
            }
            byte[] hashed = digest.digest(rawPassword.getBytes());
            return new String(Hex.encode(hashed));
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("密码编码失败", e);
        }
    }

    @Override
    public String encode(CharSequence rawPassword) {
        return encode(rawPassword.toString(), null);
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        // 验证时需结合业务逻辑获取对应Salt,再调用encode方法对比结果
        throw new UnsupportedOperationException("请结合业务获取Salt后调用对应encode方法完成匹配");
    }
}

2. 整合到DelegatingPasswordEncoder

若需同时支持新旧编码格式,可将自定义编码器加入DelegatingPasswordEncoder,实现新旧密码兼容:

import org.springframework.security.crypto.password.DelegatingPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import java.util.HashMap;
import java.util.Map;

public class PasswordEncoderFactory {

    public static PasswordEncoder createDelegatingPasswordEncoder() {
        // 新密码默认使用更安全的bcrypt
        String idForEncode = "bcrypt";
        Map<String, PasswordEncoder> encoders = new HashMap<>();
        
        // 添加原有编码器适配旧数据
        encoders.put("sha", new LegacyShaPasswordEncoder());
        encoders.put("sha256", new LegacyShaPasswordEncoder(256));
        
        // 添加现代安全编码器
        encoders.put("bcrypt", new org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder());
        encoders.put("pbkdf2", org.springframework.security.crypto.password.Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8());

        DelegatingPasswordEncoder delegatingEncoder = new DelegatingPasswordEncoder(idForEncode, encoders);
        // 无前缀的旧密码默认用SHA编码器匹配
        delegatingEncoder.setDefaultPasswordEncoderForMatches(new LegacyShaPasswordEncoder());
        return delegatingEncoder;
    }
}

二、StandardPasswordEncoder的替代方案

StandardPasswordEncoder已被弃用,官方推荐以下更安全的编码器:

  • BCryptPasswordEncoder:基于bcrypt哈希算法,自动生成随机Salt,安全性高,是当前主流选择:

    PasswordEncoder bcryptEncoder = new BCryptPasswordEncoder();
    String encodedPwd = bcryptEncoder.encode("rawPassword");
    boolean isMatch = bcryptEncoder.matches("rawPassword", encodedPwd);
    
  • Pbkdf2PasswordEncoder:基于PBKDF2算法,适合高安全性场景,Spring Security 5.8+提供默认配置:

    PasswordEncoder pbkdf2Encoder = Pbkdf2PasswordEncoder.defaultsForSpringSecurity_v5_8();
    
  • SCryptPasswordEncoder:基于scrypt算法,内存消耗更高,能有效抵御暴力破解:

    PasswordEncoder scryptEncoder = new org.springframework.security.crypto.scrypt.SCryptPasswordEncoder();
    

迁移注意事项

若需兼容原有StandardPasswordEncoder加密的数据,可暂时保留该编码器直至完成数据批量迁移,或编写转换逻辑将旧数据迁移至新编码格式。


内容的提问来源于stack exchange,提问作者Pranav Siddhant

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 16:33:31