【问题标题】:How to create conditional AuthenticationProvider in Spring-Security?如何在 Spring-Security 中创建条件 AuthenticationProvider?
【发布时间】:2019-07-30 20:12:16
【问题描述】:

到目前为止,我将用户名和加密密码存储在数据库中。

我的自定义UserDetailsService 从数据库中查找用户。密码是加密存储的,因此在这里应用BCryptPasswordEncoder

public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    @Autowired
    private UserDetailsService userDetailsService;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(new BCryptPasswordEncoder());
    }
}

问题:我现在必须添加一个额外的身份验证源,它提供未加密密码(我无法控制)。因此,如果在我的数据库中找不到经过身份验证的用户,我想使用未加密的密码检查其他源。但是对于这些情况,我该如何禁用BCrypt 编码器?

【问题讨论】:

  • 我现在不在我的开发机器上,但我相信有一个专门针对这个用例的复合密码编码器(在线迁移)。您可以通过前缀识别 Bcrypt 密码。
  • @chrylis 所以我必须在数据库中的所有编码密码前面加上{bcrypt},对吗?然后只依赖弹簧默认值?
  • Bcrypt 密码已经以$2a$ 为前缀。
  • 我通过不设置自己的密码编码器进行了尝试,因此加载了默认的DelegatingPasswordEncoder:以{bcrypt} 为前缀可以工作并委托给 brcypt 编码器。仅仅使用以$2a$ 开头的纯编码密码是行不通的!我可能做错了什么?
  • 我很惊讶,不太确定发生了什么,但如果它对你有用,那就太好了!

标签: java spring spring-security


【解决方案1】:

您可以配置多个身份验证提供程序,如下所示。每个身份验证提供程序都按顺序进行测试,首先成功的提供经过身份验证的数据,其他的则跳过。类似的用例以类似的方式实现,您必须首先通过数据库进行身份验证,然后 LDAP 服务器(反之亦然)也以类似的方式处理。

@Autowired
public void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authenticationProviderWithEncryptedUser);
    auth.authenticationProvider(authenticationProviderWithNonEncryptedUser);

}

【讨论】:

  • 这很棒。我使用两个DaoAuthenticationProvider 结合了这种方法,每个都有自己的UserDetailsService。而一个是我的旧 bcrypt 服务,另一个是新的非加密服务。
【解决方案2】:

几天前我也遇到了这个问题,我的旧系统数据在MD5 中加密,但新系统将密码保存在BCrypt

为了处理这个问题,我编写了一些自定义代码并使用AuthenticationProvider 而不是UserDetailsService

在这里我为你剪下我的代码

@Component
public class CustomAuthenticationProvider implements AuthenticationProvider {
    @Autowired
    LoginDao loginDao;

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

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {

        List<GrantedAuthority> grantList = new ArrayList<>();
        String name = authentication.getName();
        String password = ((String) authentication.getCredentials()).trim();
        try {
            UserModel user = loginDao.getUser(name);
            if (user != null) {
                if (passwordEncoder().matches(password, user.getLoginPass())) {
                //  System.out.println("------Good new & Strong password -----");
                    GrantedAuthority authority = new SimpleGrantedAuthority(user.getAuthotype().toString());
                    grantList.add(authority);
                }else if (password.equals(user.getLoginPass())) {//here i have md5 checker service , i remove it for your help 
                //  System.out.println("------old password! should be change it-----"); 
                    GrantedAuthority authority = new SimpleGrantedAuthority(user.getAuthotype().toString());
                    grantList.add(authority);
                }else {
                    throw new BadCredentialsException("Please enter a valid username and password.");
                }
                    return new UsernamePasswordAuthenticationToken(user, password, grantList);
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new BadCredentialsException("Please enter a valid username and password.");
        }
        throw new BadCredentialsException("Please enter a valid username and password.");
    }

    @Override
    public boolean supports(Class<? extends Object> authentication) {
        return UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication);
    }

}

并更改您的 SecurityConfiguration 课程代码

@Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider);
    }

【讨论】:

    【解决方案3】:

    根据当前文档 (https://docs.spring.io/spring-security/site/docs/current/api/org/springframework/security/crypto/password/DelegatingPasswordEncoder.html), 我只需要删除我的 .passwordEncoder() 设置器即可依赖 spring 中新的默认密码委托功能。

    然后在我的所有密码前加上 {bcrypt} 作为我的数据库密码,{noop} 作为我的新明文密码。

    【讨论】:

      猜你喜欢
      • 2016-07-19
      • 2011-01-20
      • 2012-12-23
      • 2012-01-28
      • 2016-12-07
      • 2017-05-27
      • 2013-01-27
      • 2018-09-16
      • 2019-02-06
      相关资源
      最近更新 更多