多个 WebSecurityConfigurerAdapters:spring 安全中的 JWT 身份验证和表单登录
Multiple WebSecurityConfigurerAdapters: JWT authentication and form login in spring security
我有 spring 带有 thymeleaf 的启动应用程序。我正在使用 spring 安全 formLogin 方法来确保安全,现在我只需要为某些 API 添加 JWT。
@EnableWebSecurity
public class SecurityConfigurations {
@Autowired
UserDetailsServiceImpl userDetails;
@Bean
DaoAuthenticationProvider provider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(encoder());
provider.setUserDetailsService(userDetails);
return provider;
}
@Bean
PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
@Configuration
@Order(1)
public class JWTSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Autowired
DaoAuthenticationProvider provider;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(provider);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable()
.authorizeRequests().antMatchers("/api/user/authenticate").permitAll()
.antMatchers("/api/user/**").hasRole("USER")
.and().
exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// Add a filter to validate the tokens with every request
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
@Configuration
public static class FormLoginConfigurationAdapter extends WebSecurityConfigurerAdapter {
@Autowired
DaoAuthenticationProvider provider;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(provider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/admin/admins**").hasAnyRole("SADMIN").antMatchers("/admin/**")
.hasAnyRole("ADMIN", "SADMIN", "WADMIN").antMatchers("/rest/**")
.hasAnyRole("ADMIN", "SADMIN", "WADMIN", "USER").antMatchers("/user/**").hasAnyRole("USER")
.anyRequest().permitAll().and().formLogin().loginPage("/sign-in-up")
.loginProcessingUrl("/signInProcess").usernameParameter("phone").and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/")
.invalidateHttpSession(false).and().csrf().disable().cors();
}
}
}
通过这样做,JWT 可以正常工作,但 formlogin 已停止并调用“/signInProcess”现在给出 404:
注意: 如果我更改顺序并使 formLogin @order(1) 再次工作,但当然不会工作。
我也尝试像这样将它们组合起来,现在它们都可以正常工作,但是如果 JWT 身份验证错误将出现异常处理问题 return formlogin thymeleaf 错误页面:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/admin/admins**").hasAnyRole("SADMIN").antMatchers("/admin/**")
.hasAnyRole("ADMIN", "SADMIN", "WADMIN").antMatchers("/rest/**")
.hasAnyRole("ADMIN", "SADMIN", "WADMIN", "USER").antMatchers("/user/**").hasAnyRole("USER")
.antMatchers("/api/user/authenticate").permitAll()
.antMatchers("/api/user/**").hasRole("USER")
.anyRequest().permitAll().and().formLogin().loginPage("/sign-in-up")
.loginProcessingUrl("/signInProcess").usernameParameter("phone").and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/")
.invalidateHttpSession(false).and().csrf().disable().cors();
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
任何使这项工作有效的建议。谢谢。
您的 WebSecurityConfigurerAdapters
将按顺序处理传入的请求。
由于 JWTSecurityConfig
被注释为 @Order(1)
它将首先处理请求。
您没有为此适配器指定 antMatcher
,因此它将匹配所有请求。
这意味着请求永远不会到达 FormLoginConfigurationAdapter
,因为 JWTSecurityConfig
匹配所有请求。
如果您希望 JWTSecurityConfig
仅应用于某些请求,您可以在安全配置中指定 antMatcher
。
下面是一个例子:
@EnableWebSecurity
public class SecurityConfigurations {
@Configuration
@Order(1)
public class JWTSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers(matchers -> matchers
.antMatchers("/api/**") // apply JWTSecurityConfig to requests matching "/api/**"
)
.authorizeRequests(authz -> authz
.anyRequest().authenticated()
)
.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
@Configuration
public class FormLoginConfigurationAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(authz -> authz
.anyRequest().authenticated()
)
.formLogin();
}
}
}
有关多个 WebSecurityConfigurerAdapter
的更多详细信息,您可以参阅 Spring 安全参考文档中的 multiple HttpSecurity
部分。
authorizeRequests()
和requestMatchers()
的区别可以看this Stack Overflow question.
我有 spring 带有 thymeleaf 的启动应用程序。我正在使用 spring 安全 formLogin 方法来确保安全,现在我只需要为某些 API 添加 JWT。
@EnableWebSecurity
public class SecurityConfigurations {
@Autowired
UserDetailsServiceImpl userDetails;
@Bean
DaoAuthenticationProvider provider() {
DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
provider.setPasswordEncoder(encoder());
provider.setUserDetailsService(userDetails);
return provider;
}
@Bean
PasswordEncoder encoder() {
return new BCryptPasswordEncoder();
}
@Configuration
@Order(1)
public class JWTSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;
@Autowired
private JwtRequestFilter jwtRequestFilter;
@Autowired
DaoAuthenticationProvider provider;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(provider);
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
@Override
protected void configure(HttpSecurity httpSecurity) throws Exception {
httpSecurity.csrf().disable()
.authorizeRequests().antMatchers("/api/user/authenticate").permitAll()
.antMatchers("/api/user/**").hasRole("USER")
.and().
exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint).and().sessionManagement()
.sessionCreationPolicy(SessionCreationPolicy.STATELESS);
// Add a filter to validate the tokens with every request
httpSecurity.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
@Configuration
public static class FormLoginConfigurationAdapter extends WebSecurityConfigurerAdapter {
@Autowired
DaoAuthenticationProvider provider;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(provider);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/admin/admins**").hasAnyRole("SADMIN").antMatchers("/admin/**")
.hasAnyRole("ADMIN", "SADMIN", "WADMIN").antMatchers("/rest/**")
.hasAnyRole("ADMIN", "SADMIN", "WADMIN", "USER").antMatchers("/user/**").hasAnyRole("USER")
.anyRequest().permitAll().and().formLogin().loginPage("/sign-in-up")
.loginProcessingUrl("/signInProcess").usernameParameter("phone").and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/")
.invalidateHttpSession(false).and().csrf().disable().cors();
}
}
}
通过这样做,JWT 可以正常工作,但 formlogin 已停止并调用“/signInProcess”现在给出 404:
注意: 如果我更改顺序并使 formLogin @order(1) 再次工作,但当然不会工作。
我也尝试像这样将它们组合起来,现在它们都可以正常工作,但是如果 JWT 身份验证错误将出现异常处理问题 return formlogin thymeleaf 错误页面:
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/admin/admins**").hasAnyRole("SADMIN").antMatchers("/admin/**")
.hasAnyRole("ADMIN", "SADMIN", "WADMIN").antMatchers("/rest/**")
.hasAnyRole("ADMIN", "SADMIN", "WADMIN", "USER").antMatchers("/user/**").hasAnyRole("USER")
.antMatchers("/api/user/authenticate").permitAll()
.antMatchers("/api/user/**").hasRole("USER")
.anyRequest().permitAll().and().formLogin().loginPage("/sign-in-up")
.loginProcessingUrl("/signInProcess").usernameParameter("phone").and().logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout")).logoutSuccessUrl("/")
.invalidateHttpSession(false).and().csrf().disable().cors();
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
任何使这项工作有效的建议。谢谢。
您的 WebSecurityConfigurerAdapters
将按顺序处理传入的请求。
由于 JWTSecurityConfig
被注释为 @Order(1)
它将首先处理请求。
您没有为此适配器指定 antMatcher
,因此它将匹配所有请求。
这意味着请求永远不会到达 FormLoginConfigurationAdapter
,因为 JWTSecurityConfig
匹配所有请求。
如果您希望 JWTSecurityConfig
仅应用于某些请求,您可以在安全配置中指定 antMatcher
。
下面是一个例子:
@EnableWebSecurity
public class SecurityConfigurations {
@Configuration
@Order(1)
public class JWTSecurityConfig extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.requestMatchers(matchers -> matchers
.antMatchers("/api/**") // apply JWTSecurityConfig to requests matching "/api/**"
)
.authorizeRequests(authz -> authz
.anyRequest().authenticated()
)
.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
}
@Configuration
public class FormLoginConfigurationAdapter extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests(authz -> authz
.anyRequest().authenticated()
)
.formLogin();
}
}
}
有关多个 WebSecurityConfigurerAdapter
的更多详细信息,您可以参阅 Spring 安全参考文档中的 multiple HttpSecurity
部分。
authorizeRequests()
和requestMatchers()
的区别可以看this Stack Overflow question.