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

Spring Security JDBC认证自定义查询与Oracle哈希密码校验实现

Spring Security 适配存量Oracle库实现自定义用户查询与密码校验方案

步骤1:实现自定义UserDetailsService完成用户信息查询

Spring Security默认的JDBC用户查询逻辑绑定了固定表结构,你可以通过重写UserDetailsService接口的loadUserByUsername方法,对接自己的存量业务表:

@Service
public class CustomUserDetailsService implements UserDetailsService {

    @Resource
    private JdbcTemplate jdbcTemplate;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        // 替换为实际业务库的用户查询SQL,字段对应自己的表结构
        String userQuerySql = "select user_account, user_pwd, is_enabled from biz_employee where user_account = ?";
        try {
            return jdbcTemplate.queryForObject(userQuerySql, new String[]{username}, (rs, rowNum) -> {
                String account = rs.getString("user_account");
                String password = rs.getString("user_pwd");
                boolean enabled = rs.getBoolean("is_enabled");
                // 可补充权限查询逻辑,封装到权限列表中
                List<GrantedAuthority> authorities = AuthorityUtils.createAuthorityList("ROLE_EMPLOYEE");
                return new User(account, password, enabled, true, true, true, authorities);
            });
        } catch (EmptyResultDataAccessException e) {
            throw new UsernameNotFoundException("用户名不存在");
        }
    }
}

步骤2:实现自定义PasswordEncoder适配Oracle原生哈希逻辑

根据存量库的Oracle哈希规则,重写PasswordEncoder接口的加密和比对方法,保证逻辑完全对齐:

@Component
public class OracleHashPasswordEncoder implements PasswordEncoder {

    // 替换为实际Oracle使用的哈希算法,比如SHA-256对应"SHA-256",SHA-1对应"SHA-1"
    private static final String HASH_ALGORITHM = "SHA-256";

    @Override
    public String encode(CharSequence rawPassword) {
        try {
            MessageDigest digest = MessageDigest.getInstance(HASH_ALGORITHM);
            byte[] hashBytes = digest.digest(rawPassword.toString().getBytes(StandardCharsets.UTF_8));
            // 转换为和Oracle存储一致的十六进制格式,大小写要和存量库对齐
            StringBuilder hexStr = new StringBuilder();
            for (byte b : hashBytes) {
                String hex = Integer.toHexString(0xff & b);
                if (hex.length() == 1) hexStr.append('0');
                hexStr.append(hex);
            }
            // Oracle默认返回大写十六进制,如有特殊规则自行调整
            return hexStr.toString().toUpperCase();
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("不支持的哈希算法", e);
        }
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        return encode(rawPassword).equals(encodedPassword);
    }
}

补充说明:如果存量密码加密用到了固定盐或者用户独立盐,独立盐可以在查询用户信息时一同查出,封装到自定义的UserDetails实现类中,在加密时取出盐参与运算即可。

步骤3:注册自定义实现到Spring Security配置

将上面两个自定义类注入到Security配置中,替换默认实现:

@Configuration
@EnableWebSecurity
public class SecurityConfig {

    @Resource
    private CustomUserDetailsService customUserDetailsService;
    @Resource
    private OracleHashPasswordEncoder oraclePasswordEncoder;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests(auth -> auth
                .anyRequest().authenticated()
            )
            .formLogin(Customizer.withDefaults());
        return http.build();
    }

    @Bean
    public AuthenticationProvider authenticationProvider() {
        DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
        provider.setUserDetailsService(customUserDetailsService);
        provider.setPasswordEncoder(oraclePasswordEncoder);
        return provider;
    }
}

校验前置验证建议

  • 先在Oracle中执行测试SQL确认哈希规则:select DBMS_CRYPTO.HASH(UTL_I18N.STRING_TO_RAW('测试明文密码', 'AL32UTF8'), 6) from dual,其中参数6对应SHA-256,3对应SHA-1,4对应MD5,和Java加密结果对比一致后再接入流程
  • 确认存量库密文的格式:是否有固定前缀、大小写规则,避免格式差异导致比对失败

内容的提问来源于stack exchange,提问作者Jonathan Ato Markin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.29 18:54:03