Spring安全迁移到6:不接受JSESSIONID cookie(401)

rvpgvaaj  于 2023-08-02  发布在  Spring
关注(0)|答案(1)|浏览(112)

我使用的是Sping Boot 2.7,我更改为Spring Boot 3,所以Spring Security更改为6。
我以前的配置是:

@Bean
  public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
     .csrf().disable()
     .cors().and()
     .authorizeRequests().anyRequest().authenticated().and()
     .httpBasic().authenticationEntryPoint(authenticationEntryPoint()).and()
     .logout().logoutSuccessHandler(logoutSuccessHandler());
    return http.build();
  }

  private AuthenticationEntryPoint authenticationEntryPoint() {
    return new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED);
  }

  private LogoutSuccessHandler logoutSuccessHandler() {
    return new HttpStatusReturningLogoutSuccessHandler(HttpStatus.OK);
  }

字符串
我改为:

@Bean
  public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        .csrf(AbstractHttpConfigurer::disable)
        .cors(withDefaults())
        .authorizeHttpRequests(authorizeHttpRequestsConfigurer -> authorizeHttpRequestsConfigurer./*requestMatchers(GET, SWAGGER_WHITELIST).permitAll().*/anyRequest().authenticated())
        .httpBasic(httpBasicConfigurer -> httpBasicConfigurer.authenticationEntryPoint(authenticationEntryPoint()))
        .logout(logoutConfigurer -> logoutConfigurer.logoutSuccessHandler(logoutSuccessHandler()));
    return http.build();
  }


我也改了:

@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)


致:

@EnableWebSecurity
@EnableMethodSecurity(securedEnabled = true)


现在,包含Authorization头的请求工作正常:

18:36:00.823 [http-nio-8080-exec-6] DEBUG o.s.security.web.FilterChainProxy - Securing GET /users/current
18:36:00.924 [http-nio-8080-exec-6] DEBUG o.s.s.w.a.w.BasicAuthenticationFilter - Set SecurityContextHolder to UsernamePasswordAuthenticationToken [Principal=com.example.UserDetailsAdapter@e98a174, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[ROLE_ADMIN]]
18:36:00.925 [http-nio-8080-exec-6] DEBUG o.s.security.web.FilterChainProxy - Secured GET /users/current


该请求还设置cookie JSESSIONID。但是下一个只使用cookie(没有授权头)的请求返回401。
日志包括:

18:36:00.948 [http-nio-8080-exec-7] DEBUG o.s.security.web.FilterChainProxy - Securing GET /users/current
18:36:00.949 [http-nio-8080-exec-7] DEBUG o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to anonymous SecurityContext


我真的不知道在迁移中失败了什么,有什么建议吗?
先谢谢你。
更新:
包含auth头的请求日志(运行良好,返回200):

19:26:39.633 [http-nio-8080-exec-1] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring DispatcherServlet 'dispatcherServlet'
19:26:39.633 [http-nio-8080-exec-1] INFO  o.s.web.servlet.DispatcherServlet - Initializing Servlet 'dispatcherServlet'
19:26:39.635 [http-nio-8080-exec-1] INFO  o.s.web.servlet.DispatcherServlet - Completed initialization in 2 ms
19:26:39.695 [http-nio-8080-exec-1] TRACE o.s.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=any request, Filters=[org.springframework.security.web.session.DisableEncodeUrlFilter@4a0c04ab, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@453439e, org.springframework.security.web.context.SecurityContextHolderFilter@71de1091, org.springframework.security.web.header.HeaderWriterFilter@50008974, org.springframework.web.filter.CorsFilter@2d33795c, org.springframework.security.web.authentication.logout.LogoutFilter@1d1deb11, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@2aac87ab, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@53dbe7b2, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@520ec7a7, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@779ef5cb, org.springframework.security.web.access.ExceptionTranslationFilter@3a7dcfb7, org.springframework.security.web.access.intercept.AuthorizationFilter@a11efe6]] (1/1)
19:26:39.696 [http-nio-8080-exec-1] DEBUG o.s.security.web.FilterChainProxy - Securing OPTIONS /users/current
19:26:39.698 [http-nio-8080-exec-1] TRACE o.s.security.web.FilterChainProxy - Invoking DisableEncodeUrlFilter (1/12)
19:26:39.701 [http-nio-8080-exec-1] TRACE o.s.security.web.FilterChainProxy - Invoking WebAsyncManagerIntegrationFilter (2/12)
19:26:39.703 [http-nio-8080-exec-1] TRACE o.s.security.web.FilterChainProxy - Invoking SecurityContextHolderFilter (3/12)
19:26:39.704 [http-nio-8080-exec-1] TRACE o.s.security.web.FilterChainProxy - Invoking HeaderWriterFilter (4/12)
19:26:39.705 [http-nio-8080-exec-1] TRACE o.s.security.web.FilterChainProxy - Invoking CorsFilter (5/12)
19:26:39.723 [http-nio-8080-exec-1] TRACE o.s.s.w.h.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match request to [Is Secure]
19:26:39.730 [http-nio-8080-exec-2] TRACE o.s.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=any request, Filters=[org.springframework.security.web.session.DisableEncodeUrlFilter@4a0c04ab, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@453439e, org.springframework.security.web.context.SecurityContextHolderFilter@71de1091, org.springframework.security.web.header.HeaderWriterFilter@50008974, org.springframework.web.filter.CorsFilter@2d33795c, org.springframework.security.web.authentication.logout.LogoutFilter@1d1deb11, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@2aac87ab, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@53dbe7b2, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@520ec7a7, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@779ef5cb, org.springframework.security.web.access.ExceptionTranslationFilter@3a7dcfb7, org.springframework.security.web.access.intercept.AuthorizationFilter@a11efe6]] (1/1)
19:26:39.730 [http-nio-8080-exec-2] DEBUG o.s.security.web.FilterChainProxy - Securing GET /users/current
19:26:39.730 [http-nio-8080-exec-2] TRACE o.s.security.web.FilterChainProxy - Invoking DisableEncodeUrlFilter (1/12)
19:26:39.731 [http-nio-8080-exec-2] TRACE o.s.security.web.FilterChainProxy - Invoking WebAsyncManagerIntegrationFilter (2/12)
19:26:39.731 [http-nio-8080-exec-2] TRACE o.s.security.web.FilterChainProxy - Invoking SecurityContextHolderFilter (3/12)
19:26:39.731 [http-nio-8080-exec-2] TRACE o.s.security.web.FilterChainProxy - Invoking HeaderWriterFilter (4/12)
19:26:39.732 [http-nio-8080-exec-2] TRACE o.s.security.web.FilterChainProxy - Invoking CorsFilter (5/12)
19:26:39.735 [http-nio-8080-exec-2] TRACE o.s.security.web.FilterChainProxy - Invoking LogoutFilter (6/12)
19:26:39.736 [http-nio-8080-exec-2] TRACE o.s.s.w.a.logout.LogoutFilter - Did not match request to Or [Ant [pattern='/logout', GET], Ant [pattern='/logout', POST], Ant [pattern='/logout', PUT], Ant [pattern='/logout', DELETE]]
19:26:39.736 [http-nio-8080-exec-2] TRACE o.s.security.web.FilterChainProxy - Invoking BasicAuthenticationFilter (7/12)
19:26:39.738 [http-nio-8080-exec-2] TRACE o.s.s.w.a.w.BasicAuthenticationFilter - Found username 'usp' in Basic Authorization header
19:26:39.738 [http-nio-8080-exec-2] TRACE o.s.s.w.c.HttpSessionSecurityContextRepository - No HttpSession currently exists
19:26:39.738 [http-nio-8080-exec-2] TRACE o.s.s.w.c.SupplierDeferredSecurityContext - Created SecurityContextImpl [Null authentication]
19:26:39.739 [http-nio-8080-exec-2] TRACE o.s.s.w.c.SupplierDeferredSecurityContext - Created SecurityContextImpl [Null authentication]
19:26:39.960 [http-nio-8080-exec-2] DEBUG o.s.s.w.a.w.BasicAuthenticationFilter - Set SecurityContextHolder to UsernamePasswordAuthenticationToken [Principal=com.example.UserDetailsAdapter@13ea0982, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[ROLE_ADMIN]]
19:26:39.961 [http-nio-8080-exec-2] TRACE o.s.security.web.FilterChainProxy - Invoking RequestCacheAwareFilter (8/12)
19:26:39.961 [http-nio-8080-exec-2] TRACE o.s.s.w.s.HttpSessionRequestCache - matchingRequestParameterName is required for getMatchingRequest to lookup a value, but not provided
19:26:39.961 [http-nio-8080-exec-2] TRACE o.s.security.web.FilterChainProxy - Invoking SecurityContextHolderAwareRequestFilter (9/12)
19:26:39.962 [http-nio-8080-exec-2] TRACE o.s.security.web.FilterChainProxy - Invoking AnonymousAuthenticationFilter (10/12)
19:26:39.962 [http-nio-8080-exec-2] TRACE o.s.security.web.FilterChainProxy - Invoking ExceptionTranslationFilter (11/12)
19:26:39.963 [http-nio-8080-exec-2] TRACE o.s.security.web.FilterChainProxy - Invoking AuthorizationFilter (12/12)
19:26:39.964 [http-nio-8080-exec-2] TRACE o.s.s.w.a.i.RequestMatcherDelegatingAuthorizationManager - Authorizing SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@523c08be]
19:26:39.965 [http-nio-8080-exec-2] TRACE o.s.s.w.a.i.RequestMatcherDelegatingAuthorizationManager - Checking authorization on SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@523c08be] using org.springframework.security.authorization.AuthenticatedAuthorizationManager@55258ae6
19:26:39.965 [http-nio-8080-exec-2] TRACE o.s.s.w.a.AnonymousAuthenticationFilter - Did not set SecurityContextHolder since already authenticated UsernamePasswordAuthenticationToken [Principal=com.example.UserDetailsAdapter@13ea0982, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[ROLE_ADMIN]]


没有auth头的请求日志,但有JSESSIONID(工作不好,返回401):

19:26:39.967 [http-nio-8080-exec-2] DEBUG o.s.security.web.FilterChainProxy - Secured GET /users/current
19:26:40.032 [http-nio-8080-exec-2] TRACE o.s.s.w.h.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match request to [Is Secure]
19:26:40.064 [http-nio-8080-exec-3] TRACE o.s.security.web.FilterChainProxy - Trying to match request against DefaultSecurityFilterChain [RequestMatcher=any request, Filters=[org.springframework.security.web.session.DisableEncodeUrlFilter@4a0c04ab, org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@453439e, org.springframework.security.web.context.SecurityContextHolderFilter@71de1091, org.springframework.security.web.header.HeaderWriterFilter@50008974, org.springframework.web.filter.CorsFilter@2d33795c, org.springframework.security.web.authentication.logout.LogoutFilter@1d1deb11, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@2aac87ab, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@53dbe7b2, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@520ec7a7, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@779ef5cb, org.springframework.security.web.access.ExceptionTranslationFilter@3a7dcfb7, org.springframework.security.web.access.intercept.AuthorizationFilter@a11efe6]] (1/1)
19:26:40.066 [http-nio-8080-exec-3] DEBUG o.s.security.web.FilterChainProxy - Securing GET /users/current
19:26:40.066 [http-nio-8080-exec-3] TRACE o.s.security.web.FilterChainProxy - Invoking DisableEncodeUrlFilter (1/12)
19:26:40.067 [http-nio-8080-exec-3] TRACE o.s.security.web.FilterChainProxy - Invoking WebAsyncManagerIntegrationFilter (2/12)
19:26:40.068 [http-nio-8080-exec-3] TRACE o.s.security.web.FilterChainProxy - Invoking SecurityContextHolderFilter (3/12)
19:26:40.068 [http-nio-8080-exec-3] TRACE o.s.security.web.FilterChainProxy - Invoking HeaderWriterFilter (4/12)
19:26:40.068 [http-nio-8080-exec-3] TRACE o.s.security.web.FilterChainProxy - Invoking CorsFilter (5/12)
19:26:40.069 [http-nio-8080-exec-3] TRACE o.s.security.web.FilterChainProxy - Invoking LogoutFilter (6/12)
19:26:40.070 [http-nio-8080-exec-3] TRACE o.s.s.w.a.logout.LogoutFilter - Did not match request to Or [Ant [pattern='/logout', GET], Ant [pattern='/logout', POST], Ant [pattern='/logout', PUT], Ant [pattern='/logout', DELETE]]
19:26:40.070 [http-nio-8080-exec-3] TRACE o.s.security.web.FilterChainProxy - Invoking BasicAuthenticationFilter (7/12)
19:26:40.070 [http-nio-8080-exec-3] TRACE o.s.s.w.a.w.BasicAuthenticationFilter - Did not process authentication request since failed to find username and password in Basic Authorization header
19:26:40.070 [http-nio-8080-exec-3] TRACE o.s.security.web.FilterChainProxy - Invoking RequestCacheAwareFilter (8/12)
19:26:40.070 [http-nio-8080-exec-3] TRACE o.s.s.w.s.HttpSessionRequestCache - matchingRequestParameterName is required for getMatchingRequest to lookup a value, but not provided
19:26:40.070 [http-nio-8080-exec-3] TRACE o.s.security.web.FilterChainProxy - Invoking SecurityContextHolderAwareRequestFilter (9/12)
19:26:40.071 [http-nio-8080-exec-3] TRACE o.s.security.web.FilterChainProxy - Invoking AnonymousAuthenticationFilter (10/12)
19:26:40.071 [http-nio-8080-exec-3] TRACE o.s.security.web.FilterChainProxy - Invoking ExceptionTranslationFilter (11/12)
19:26:40.071 [http-nio-8080-exec-3] TRACE o.s.security.web.FilterChainProxy - Invoking AuthorizationFilter (12/12)
19:26:40.071 [http-nio-8080-exec-3] TRACE o.s.s.w.a.i.RequestMatcherDelegatingAuthorizationManager - Authorizing SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@585e8e91]
19:26:40.071 [http-nio-8080-exec-3] TRACE o.s.s.w.a.i.RequestMatcherDelegatingAuthorizationManager - Checking authorization on SecurityContextHolderAwareRequestWrapper[ org.springframework.security.web.header.HeaderWriterFilter$HeaderWriterRequest@585e8e91] using org.springframework.security.authorization.AuthenticatedAuthorizationManager@55258ae6
19:26:40.071 [http-nio-8080-exec-3] TRACE o.s.s.w.c.HttpSessionSecurityContextRepository - No HttpSession currently exists
19:26:40.071 [http-nio-8080-exec-3] TRACE o.s.s.w.c.SupplierDeferredSecurityContext - Created SecurityContextImpl [Null authentication]
19:26:40.071 [http-nio-8080-exec-3] TRACE o.s.s.w.c.SupplierDeferredSecurityContext - Created SecurityContextImpl [Null authentication]
19:26:40.078 [http-nio-8080-exec-3] TRACE o.s.s.w.a.AnonymousAuthenticationFilter - Set SecurityContextHolder to AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]]
19:26:40.081 [http-nio-8080-exec-3] TRACE o.s.s.w.a.ExceptionTranslationFilter - Sending AnonymousAuthenticationToken [Principal=anonymousUser, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1, SessionId=null], Granted Authorities=[ROLE_ANONYMOUS]] to authentication entry point since access is denied
org.springframework.security.access.AccessDeniedException: Access Denied
    at org.springframework.security.web.access.intercept.AuthorizationFilter.doFilter(AuthorizationFilter.java:98)
    at org.springframework.security.web.ObservationFilterChainDecorator$ObservationFilter.wrapFilter(ObservationFilterChainDecorator.java:240)
...
19:26:40.093 [http-nio-8080-exec-3] TRACE o.s.s.w.s.HttpSessionRequestCache - Did not save request since it did not match [And [Not [Ant [pattern='/**/favicon.*']], Not [MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@3c0e8c92, matchingMediaTypes=[application/json], useEquals=false, ignoredMediaTypes=[*/*]]], Not [RequestHeaderRequestMatcher [expectedHeaderName=X-Requested-With, expectedHeaderValue=XMLHttpRequest]], Not [MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@3c0e8c92, matchingMediaTypes=[multipart/form-data], useEquals=false, ignoredMediaTypes=[*/*]]], Not [MediaTypeRequestMatcher [contentNegotiationStrategy=org.springframework.web.accept.ContentNegotiationManager@3c0e8c92, matchingMediaTypes=[text/event-stream], useEquals=false, ignoredMediaTypes=[*/*]]]]]
19:26:40.094 [http-nio-8080-exec-3] TRACE o.s.s.w.h.writers.HstsHeaderWriter - Not injecting HSTS header since it did not match request to [Is Secure]

xe55xuns

xe55xuns1#

5.8 migration guide概述了使用SecurityContextRepository保存SecurityContext的更改。每个身份验证过滤器现在负责保存SecurityContext。由于HTTP基本身份验证是无状态的,BasicAuthenticationFilter不会将SecurityContext保存到会话中,因此 * 不会 * 触发会话的创建。

**注意:**请不要关闭CSRF保护。无论您的应用程序是使用会话还是HTTP基本身份验证,都容易受到CSRF攻击。

话虽如此,如果您的环境中有什么东西触发了会话创建(不清楚您的问题是什么,因为它缺少一些细节),您可能会看到一个JSESSIONID,但您之前请求的SecurityContext不会通过提供该cookie而恢复。您需要为每个请求提供凭据。
如果这一重大变更影响到您,并且您无法更改您的客户(例如:浏览器应用程序)来执行此操作,或者您有不想执行此操作的原因(例如在每个请求上验证凭据的性能),您有几个选项。
1.您可以恢复5.8和更早版本的默认值,即每次请求时保存SecurityContext。一般情况下不建议这样做,但在此期间可以很好地帮助您完成迁移。

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        // ...
        .securityContext((securityContext) -> securityContext
            .requireExplicitSave(false)
        );
    return http.build();
}

字符串
1.您可以自己保存SecurityContext,但需要调用自定义/login端点来触发此操作。

@RestController
class LoginController {

    private final SecurityContextHolderStrategy contextHolderStrategy =
            SecurityContextHolder.getContextHolderStrategy();

    private final HttpSessionSecurityContextRepository securityContextRepository =
        new HttpSessionSecurityContextRepository();

    @PostMapping("/login")
    @ResponseStatus(HttpStatus.NO_CONTENT)
    public void login(
            HttpServletRequest request,
            HttpServletResponse response,
            Authentication authentication) {

        var securityContext = this.contextHolderStrategy.createEmptyContext();
        securityContext.setAuthentication(authentication);
        this.securityContextRepository.saveContext(securityContext, request, response);
    }

}


1.您可以自定义Spring Security的BasicAuthenticationFilter来保存SecurityContext。不建议这样做,因为这是一种不常见的配置,因此没有内置到DSL中。

@Bean 
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
        // ...
        .httpBasic((httpBasic) -> httpBasic
            .withObjectPostProcessor(new ObjectPostProcessor<BasicAuthenticationFilter>() {
                @Override
                public <O extends BasicAuthenticationFilter> O postProcess(O filter) {
                    filter.setSecurityContextRepository(new HttpSessionSecurityContextRepository());
                    return filter;
                }
            })
        );
    return http.build();
}

相关问题