java - 带有 Spring Boot : Mix Basic Authentication with JWT token authentication 的 Spring Security

标签 java spring-boot spring-security jwt

<分区>

我试图让 Spring Security 的基本身份验证与 JWT token 身份验证并肩工作,但没有成功。我已经为我的 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 错误。 任何帮助将不胜感激。

最佳答案

原因是ApiWebSecurityConfigurationAdapterFormLoginWebSecurityConfig都没有使用antMatcher()。这意味着两种安全配置都将处理所有路径,即使您之后使用 antMatchers() 也是如此。因此,最低阶的配置 (@Order(1)) 将处理所有事情,而另一个什么都不做。

docs 中也提到了这一点:

The http.antMatcher states that this HttpSecurity will only be applicable to URLs that start with /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()?

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

另请注意,您可能必须更改顺序。您应该将配置放在最详细的 antMatcher() 上,在本例中为 FormLoginWebSecurityConfig

关于java - 带有 Spring Boot : Mix Basic Authentication with JWT token authentication 的 Spring Security,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48221131/

相关文章:

java - 扩展 AsyncTask 而不覆盖其参数

java - 当我在java中运行进程时如何获取processid?

java - 如何在 Spring 中以编程方式生成新的托管 bean

spring-boot - 为什么 SpringFox 不暴露@RepositoryRestResource?

java - Spring Security 条件基本身份验证

java - 为什么在第二种情况下不允许字符串连接?

java - 使用 android 媒体播放器播放不断变化的文件

java - 通过使用 JAXB 解码将 XML 转换为对象

Spring 对每个未经授权的 HTTP POST 返回 HTTP 405

spring-security - Acegi 安全 : How do i add another GrantedAuthority to Authentication to anonymous user