Spring Boot with Spring Boot:将基本身份验证与JWT令牌身份验证相结合

时间:2018-01-12 07:00:57

标签: java spring-boot spring-security jwt

我试图让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)注释的配置是Spring Security选择的配置,另一个完全被忽略。就像上面的配置一样,如果我尝试访问/ console / login,我会收到401错误。 任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:2)

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

docs中也提到了这一点:

  

http.antMatcher表示此HttpSecurity仅适用于以/api/开头的网址

因此,要解决此问题,您必须为您的某个配置(或两者)添加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();
}

关于这个主题的另一个好读物是这个问题:When to use Spring Security`s antMatcher()?

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

另请注意,您可能需要更改订单。您应该在配置中使用最详细的antMatcher()订购,在这种情况下为FormLoginWebSecurityConfig