Spring Security返回403而不是401,并创建无效的Redis会话cookie

问题描述

我正在使用Spring Security和Spring Data Redis来跟踪具有自定义角色和权利的用户会话。当我尝试在浏览器中访问没有会话cookie的预授权端点时,它应该返回401。相反,会创建一个新的(无效)会话cookie,并且端点返回403。

这是我的SecurityConfig

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true,order = Ordered.HIGHEST_PRECEDENCE)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests((authorize) -> authorize
                        .requestMatchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
                        .anyRequest().authenticated()
                )

                // SameSite=Strict;
                .csrf().disable().cors();
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);

        config.addAllowedOrigin("*");

        config.addAllowedMethod(HttpMethod.GET);
        config.addAllowedMethod(HttpMethod.POST);
        config.addAllowedMethod(HttpMethod.DELETE);
        config.addAllowedMethod(HttpMethod.OPTIONS);
        config.addAllowedHeader("Authorization");
        config.addAllowedHeader("Content-Type");
        config.addAllowedHeader("*");
        source.registerCorsConfiguration("/**",config);
        return new CorsFilter(source);
    }
}

我还使用MethodSecurityConfigUserDetails的实现来解析用户身份验证中的自定义字段

解决方法

这是解决的方法,适用于任何遇到类似问题的人:

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.NEVER).and()   //let redis handle session creation
                .csrf().disable().cors().and()
                .requestCache().disable().exceptionHandling().and()                         //prevent exception creating duplicate session
                .authorizeRequests().anyRequest().authenticated().and()                     //all endpoints need auth
                .exceptionHandling().authenticationEntryPoint(
                        new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));                 //return 401 on no session
    }