【问题标题】:How can I pass the salt to Spring?我怎样才能把盐传给春天?
【发布时间】:2017-10-03 16:27:09
【问题描述】:

我正在 Spring Boot 中实施 OAuth 2.0。当用户传递他的用户名/密码时,spring 会尝试通过对密码进行散列并将其与我传递给它的已经散列的密码进行比较来对其进行身份验证。但是,Spring 总是错过了盐,所以它总是返回错误的凭据。

如何将盐传递给 Spring?

这是我的 UserDAO 类:

@Service
public class UserDAO implements UserDetailsService, SaltSource{

private LoginDetails user;
private UserDetailsImpl userDetailsImpl;

@Autowired
private LoginDetailsManager loginDetailsManager;

@Override
public UserDetails1 loadUserByUsername(String username) throws UsernameNotFoundException {

    System.out.println("Get user");
    user = loginDetailsManager.getByUsername(username);
    System.out.println(user.toString());
    if (user == null) {
        throw new UsernameNotFoundException(
                "User " + username + " not found.");
    }

    GrantedAuthority grantedAuthority = new SimpleGrantedAuthority("ROLE_USER");
    List<GrantedAuthority> grantedAuthorities = new ArrayList<>();
    grantedAuthorities.add(grantedAuthority);

    String password = user.getPasswordHash();
    String salt = user.getSalt();
    userDetailsImpl = new UserDetailsImpl(user.getUsername(), user.getPasswordHash(), salt, grantedAuthorities);

    return new UserDetailsImpl(
            user.getUsername(),
            user.getPasswordHash(),
            salt,
            grantedAuthorities);
}
}

以下是我的 AuthorizationServer 类:

@Configuration
@EnableAuthorizationServer
protected class AuthorizationApplication extends AuthorizationServerConfigurerAdapter {

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new StandardPasswordEncoder();
    }

    @Autowired
    private PasswordEncoder passwordEncoder;

    @Autowired
    private AuthenticationManager authenticationManager;


    @Bean
    protected AuthorizationCodeServices getAuthorizationCodeServices() {
        return new JdbcAuthorizationCodeServices(dataSource);
    }


    @Override
    public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
        clients.jdbc(dataSource);
    }


    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        AuthorizationCodeServices services = getAuthorizationCodeServices();
        JdbcTokenStore tokenStore = getTokenStore();
        endpoints
                .userDetailsService(userDetailsService)
                .authorizationCodeServices(services)
                .authenticationManager(authenticationManager)
                .tokenStore(tokenStore)
                .approvalStoreDisabled();
    }

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.allowFormAuthenticationForClients();
        security.passwordEncoder(passwordEncoder);
    }

通过一点调试,我发现 Spring 从 SaltSource (org.springframework.security.authentication.dao.SaltSource) 获取它的盐。我无法弄清楚如何配置该来源。

【问题讨论】:

  • 因为我的数据库中有 SHA256(hash+password) - 我从 UserDAO 类返回到 Spring 作为 UserDetailsImpl 对象的属性user.getPasswordHash()。 Spring 正在将其与 SHA256(密码)进行比较,我未经授权。
  • 对不起,我没听懂。目前,我有一个手动填充的数据库进行测试。如果没有盐,spring 将如何进行身份验证?
  • 好的,请多多包涵。为了避免复杂性,我刚刚创建了一个实现 PasswordEncoder 的新类(使用两种方法 - 用于简单 sha256 散列的编码和 match())并开始使用它而不是 StandardPasswordEncoder。有没有办法为此配置 SaltSource?
  • 我正在实现PasswordEncoder,但在DaoAuthenticationProvider 类中,我发现:与加密模块PasswordEncoder 一起使用时,Salt 值必须为空。不再执行它没有意义。有没有其他方法可以解决这个问题?
  • 如果您使用 BCryptPasswordEncoder,那么您不必担心加盐,因为它会自动加盐您的密码。

标签: java spring spring-boot spring-security oauth-2.0


【解决方案1】:

想不出办法,因此实现了我自己的PasswordEncoder 并使用静态变量从UserDAO 传递盐:

public class PasswordEncoderImpl implements PasswordEncoder {

    public static Constants constants = new Constants();

    @Override
    public String encode(CharSequence rawPassword) {
        return DigestUtils.sha256Hex(rawPassword.toString());
    }

    @Override
    public boolean matches(CharSequence rawPassword, String encodedPassword) {
        String salt = constants.getSalt();

/**
 * If salt is null, it means the value in constants object is empty now.
 * => client-secret validation is going on
 * => we just need the comparision of plain-text string.
 */
        if(salt != null) {
//    case of password authentication
            return DigestUtils.sha256Hex(salt + rawPassword).equalsIgnoreCase(encodedPassword);
        } else {
    //case of client-secret authentication
        return rawPassword.equals(encodedPassword);
        }
    }
}

loadUserByUsername方法中设置常量对象的值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-01-28
    • 2018-03-26
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-12
    • 2012-01-07
    • 1970-01-01
    相关资源
    最近更新 更多