小编典典

使用Spring Boot的Spring Security:将基本身份验证与JWT令牌身份验证混合

spring-boot

我试图让Spring
Security的基本身份验证与JWT令牌身份验证并存,但没有成功。我已经为Web控制台和JWT实现了基本身份验证,以保护许多API端点。这是我的配置:

@EnableGlobalMethodSecurity(prePostEnabled = true)
public class MultiHttpSecurityConfig {

@Autowired
private UserDetailsService userDetailsService;

@Autowired
public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
    authenticationManagerBuilder
            .userDetailsService(this.userDetailsService)
            .passwordEncoder(bCryptPasswordEncoder());
}

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

/**
 * 
 * API Security configuration
 *
 */
@Configuration
@Order(1) 
public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter{

    @Bean
    public JwtAuthenticationTokenFilter authenticationTokenFilterBean() throws Exception {
        return new JwtAuthenticationTokenFilter();
    }

    @Autowired
    private JwtAuthenticationEntryPoint unauthorizedHandler;

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {
    httpSecurity   
            .csrf().disable()
            .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()                
            // don't create session
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
            .authorizeRequests().antMatchers("/api/**","/refresh/**").authenticated()
            .antMatchers("/auth/**").permitAll().anyRequest().authenticated();               
        // Custom JWT based security filter
        httpSecurity.addFilterBefore(authenticationTokenFilterBean(), UsernamePasswordAuthenticationFilter.class);
        // disable page caching
        httpSecurity.headers().cacheControl();
    }
}

/**
 * 
 * Form login security configuration
 *
 */
@Configuration
public static class FormLoginWebSecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private ConsoleAuthenticationEntryPoint consoleAuthenticationEntryPoint;

    @Override
    protected void configure(HttpSecurity http) throws Exception {          
        http.httpBasic().and().exceptionHandling().authenticationEntryPoint(
                consoleAuthenticationEntryPoint).and()
         .authorizeRequests().antMatchers("/console/**").authenticated()
         .antMatchers(HttpMethod.GET,
                    "/*.html",
                    "/favicon.ico",
                    "/**/*.html",
                    "/**/*.css",
                    "/**/*.js").permitAll()
         .anyRequest().authenticated()
         .and()
         .formLogin().defaultSuccessUrl("/console/home")
         .loginPage("/console/login")
         .permitAll()
         .and()
         .logout()
         .permitAll();
        http.csrf().disable();
    }
}

}

我注意到,我用Order(1)注释的配置是SpringSecurity选择的配置,而另一个则被完全忽略。像上面的配置一样,如果尝试访问/ console
/ login,则会出现401错误。任何帮助将非常感激。


阅读 287

收藏
2020-05-30

共1个答案

小编典典

原因是因为既不使用ApiWebSecurityConfigurationAdapter也不FormLoginWebSecurityConfig使用antMatcher()。这意味着,即使您antMatchers()以后使用,这两个安全配置也将处理所有路径。因此,具有最低顺序(@Order(1))的配置将处理所有操作,而另一配置则不执行任何操作。

文档中也提到了这一点:

http.antMatcher美国,这HttpSecurity将只适用于与开头的网址/api/

因此,要解决此问题,您必须将an放置antMatcher到您的一个配置(或两个配置)中。例如,如果表单登录名应仅应用于/console/login/console/home,则可以将配置更改为:

@Override
protected void configure(HttpSecurity http) throws Exception {          
    http
        .antMatcher("/console/**") // Add this
        .httpBasic().and()
        .exceptionHandling().authenticationEntryPoint(consoleAuthenticationEntryPoint).and()
        .authorizeRequests().antMatchers("/console/**").authenticated()
        .antMatchers(HttpMethod.GET,
                "/*.html",
                "/favicon.ico",
                "/**/*.html",
                "/**/*.css",
                "/**/*.js").permitAll()
        .anyRequest().authenticated().and()
        .formLogin().defaultSuccessUrl("/console/home")
        .loginPage("/console/login").permitAll().and()
        .logout().permitAll().and() // Make sure to use .and() to add the .csrf()
        .csrf().disable();
}

请注意,您不应http像添加那样两次使用构建.csrf().disable()器,就像我在上面的代码中一样,将其添加到其他构建器中。

另请注意,您可能必须更改顺序。antMatcher()在这种情况下,您应该以最详细的顺序订购配置FormLoginWebSecurityConfig

2020-05-30