多个WebSecurityConfigurerAdapters:spring security中的JWT认证和表单登录

Posted

技术标签:

【中文标题】多个WebSecurityConfigurerAdapters:spring security中的JWT认证和表单登录【英文标题】:Multiple WebSecurityConfigurerAdapters: JWT authentication and form login in spring security 【发布时间】:2021-04-15 16:25:08 【问题描述】:

我有带有 thymeleaf 的 spring boot 应用程序。我正在使用 spring security 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 身份验证错误将返回 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);

        

任何使这项工作的建议。谢谢。

【问题讨论】:

【参考方案1】:

您的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 Security 参考文档中的multiple HttpSecurity 部分。

更多关于authorizeRequests()requestMatchers()的区别可以看this Stack Overflow question。

【讨论】:

以上是关于多个WebSecurityConfigurerAdapters:spring security中的JWT认证和表单登录的主要内容,如果未能解决你的问题,请参考以下文章

LaTeX输入单个点横向多个点竖向多个点斜向多个点

多个网格、多个 VBO、多个 VAO、OpenGL 4.1

mysql添加多个字段&删除多个字段

部分之间的多个自定义 TableviewCell 上的多个自定义 UICollectionView

Symfony 2 与多个提供商、多个防火墙和多个主机的安全问题

表示多个组的多个列[重复]