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
相关产品推荐
相关产品推荐

