Spring Security 5 - 密码迁移

Kel*_*lyM 7 java spring spring-security spring-boot

这是对早期问题的后续跟进.

我正在尝试将OAuth2应用程序迁移到Spring Boot 2/Security 5.根据我之前的问题(和)中的一条评论,似乎密码的存储格式正在发生变化.

在我原来的(Spring 1.5.9)应用程序中,我明确指定了BCrypt

// AppConfig

   @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }
Run Code Online (Sandbox Code Playgroud)

// SecurityConfig

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {


auth.userDetailsService(userService)    
.passwordEncoder(passwordEncoder);
}
Run Code Online (Sandbox Code Playgroud)

这导致错误,密码"看起来不像BCrypt(我之前的问题的原因).

感谢回复我之前的问题的评论,似乎我需要使用{bcrypt}为存储的密码添加前缀.我还用以下代码替换了我的PassowrdEncoder @Bean:

PasswordEncoder passwordEncoder =
    PasswordEncoderFactories.createDelegatingPasswordEncoder();
Run Code Online (Sandbox Code Playgroud)

但是,这导致以下错误:

java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"

接下来,我尝试将更@Bean改为以下内容:

@Bean
public PasswordEncoder passwordEncoder() {

    String idForEncode = "bcrypt";
    Map encoders = new HashMap<>();
    encoders.put(idForEncode, new BCryptPasswordEncoder());

    encoders.put("pbkdf2", new Pbkdf2PasswordEncoder());
    encoders.put("scrypt", new SCryptPasswordEncoder());

    return new DelegatingPasswordEncoder(idForEncode, encoders);

}
Run Code Online (Sandbox Code Playgroud)

这导致了同样的错误.用户创建部分似乎按预期工作.运行以下内容:

    @Bean
    public CommandLineRunner demo(UserRepository repository) {
        return(args) -> {
            OAuthUser user = new OAuthUser();


            user.setFirstName("K");
            user.setLastName("M");
            user.setPassword(passwordEncoder.encode("L"));
            user.setUserName("KLM");

repository.save(user);
        };
    }
Run Code Online (Sandbox Code Playgroud)

导致用户使用密码{bcrypt}$2a$10$p/W7UV.fkghBRMzuDhh7z.G0uPLze9yFMLarbHdmwinzlqAHrMUQi.

但是,用户验证失败.发出此请求:

curl --request POST \
  --url http://web:secret@localhost:8090/oauth/token \
  --header 'content-type: multipart/form-data; boundary=---011000010111000001101001' \
  --form grant_type=password \
  --form username=KLM \
  --form 'pasword =L'
Run Code Online (Sandbox Code Playgroud)

给出"消息":"没有为id \"null \""消息映射PasswordEncoder.

首先,任何有关问题可能出现的建议都将受到赞赏.

其次,关于迁移到新的存储格式,我还有另一个问题.这种存储格式,即{id]password标准或特定于Spring的东西?基本上,在过去,如果密码存储为BCrypt,我可能会从C#或其他应用程序验证密码.需要知道的所有应用程序是如何处理BCrypt标准.这种新的存储格式是否会抑制通过非Spring应用程序验证用户的能力?

谢谢.

编辑:

我最终让Spring Boot 2/Security 5与OAuth2一起工作.虽然我不记得确切的步骤(我一直在处理一些Spring项目),但我发布的是希望我的相关配置作为指导.

确保添加密码编码器bean:

    @Bean
    public PasswordEncoder passwordEncoder() {
return  PasswordEncoderFactories.createDelegatingPasswordEncoder();
        //return new BCryptPasswordEncoder();
    }
Run Code Online (Sandbox Code Playgroud)

对于授权服务器,请确保在AuthorizationServerSecurityConifgurerClientDetailsServiceConfigurer部分中引用它们.

  @EnableAuthorizationServer
@Configuration
public class AuthConfig extends AuthorizationServerConfigurerAdapter {

// Some code omitted for brevity

    @Override
    public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
        security.passwordEncoder(passwordEncoder);
        security.checkTokenAccess("permitAll()");
        security.tokenKeyAccess("permitAll()");
    }


    @Override
    public void configure(ClientDetailsServiceConfigurer configurer) throws Exception {
        JdbcClientDetailsService details = new JdbcClientDetailsService(appConfig.dataSource());
        details.setPasswordEncoder(passwordEncoder);

        configurer.withClientDetails(details);
    }


    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
        TokenEnhancerChain enhancerChain = new TokenEnhancerChain();
        endpoints.tokenStore(tokenStore).accessTokenConverter(converter)
        .userDetailsService(userService)
        .authenticationManager(authenticationManager);
    }
Run Code Online (Sandbox Code Playgroud)

在SecurityConfig中,确保使用AuthenticationManagerBuilder注册它.

@Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userService).passwordEncoder(passwordEncoder);
    }
Run Code Online (Sandbox Code Playgroud)

确保配置您的ResourceServer,包括HttpSecurity端点.

EnableResourceServer
@Configuration
public class ResourceConfig extends ResourceServerConfigurerAdapter {

    private AppConfig appConfig;

    @Autowired
    private ResourceServerTokenServices tokenService;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    public ResourceConfig(AuthenticationManager authenticationManager, AppConfig appConfig) {
        this.authenticationManager = authenticationManager;
        this.appConfig = appConfig;
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.resourceId("321");
        resources.tokenServices(tokenService);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http.headers().frameOptions().disable().and().requestMatchers().and().authorizeRequests()
                .antMatchers("/user/**").hasAuthority("ROLE_ADMIN").antMatchers("/h2/**").permitAll();

    }
Run Code Online (Sandbox Code Playgroud)

我相信这些@Config课程往往最相关.我的UserDetailsS​​ervice实现没有什么特别之处,我认为我甚至没有在这个应用程序中扩展或自定义客户端(在@Config中看到的内容之外).