问题描述
我正在尝试让 Spring Security 的基本身份验证与 JWT 令牌身份验证并行工作,但没有成功.我已经为我的 Web 控制台和 JWT 实现了基本身份验证,以保护许多 API 端点.这是我的配置:
I am trying to get Spring Security's basic authentication to work side by side with JWT token authentication with no success. I have implemented basic authentication for my web console and JWT to secure a number of API endpoints. Here's my config:
@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 错误.任何帮助将不胜感激.
I have noticed that the configuration I annotate with Order(1) is the one that is picked by Spring Security and the other is completely ignored. Like in the above config, I get 401 error if I try to access /console/login. Any help would be much appreciated.
推荐答案
原因是因为ApiWebSecurityConfigurationAdapter
和FormLoginWebSecurityConfig
都没有使用antMatcher()
代码>.这意味着两种安全配置都将处理所有路径,即使您之后使用 antMatchers()
也是如此.因此,具有最低顺序的配置 (@Order(1)
) 将处理所有事情,而另一个则什么也不做.
The reason why is because neither ApiWebSecurityConfigurationAdapter
nor FormLoginWebSecurityConfig
uses the antMatcher()
. This means that both security configurations will handle all paths, even though you're using antMatchers()
afterwards. Due to this, the configuration with the lowest order (@Order(1)
) will handle everything, while the other one will do nothing.
docs 中也提到了这一点:
http.antMatcher
声明此 HttpSecurity
将仅适用于以 /api/
The
http.antMatcher
states that thisHttpSecurity
will only be applicable to URLs that start with/api/
因此,要解决此问题,您必须为您的一个配置(或两者)提供一个 antMatcher
.例如,如果表单登录只应用于 /console/login
和 /console/home
,您可以将配置更改为:
So, to fix this problem, you have to povide an antMatcher
to one of your configurations (or both). For example, if the form login should only be applied to /console/login
and /console/home
, you could change the configuration to:
@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();
}
关于这个主题的另一个好读物是这个问题:何时使用 Spring Security`santMatcher()?
Another good read about this topic is this question: When to use Spring Security`s antMatcher()?
请注意,您不应像添加 .csrf().disable()
那样两次使用 http
构建器,将其添加到另一个构建器就像我在上面的代码中所做的那样.
Please note that you shouldn't use the http
builder twice like you did to add the .csrf().disable()
, add it to the other builder like I did in the code above.
另外请注意,您可能需要更改订单.您应该将顺序放在配置最详细的 antMatcher()
上,在本例中为 FormLoginWebSecurityConfig
.
Also be aware that you'll likely have to change the order. You should put the order on the configuration with the most detailed antMatcher()
, in this case FormLoginWebSecurityConfig
.
这篇关于Spring Security with Spring Boot:将基本身份验证与 JWT 令牌身份验证混合使用的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持跟版网!