Spring Security:在 SecurityContext 中找不到身份验证对象

Eri*_*cau 5 spring-security spring-boot

以下配置(filterChain)在 SpringBoot-2.7.5 中工作正常,但在我尝试在 SpringBoot-3.0.0-RC1 中测试它之后,它不起作用并显示以下消息,如果想要迁移,我需要更改任何内容到 Spring-Boot-3.0.0。谢谢。

{“timestamp”:1667794247614,“status”:401,“error”:“未经授权”,“message”:“在SecurityContext中找不到身份验证对象”,“path”:“/ api / admin / 1”}

 @Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    http.cors().and().csrf().disable()
        .exceptionHandling().authenticationEntryPoint(jwtAuthenticationProvider).and()
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
        .authorizeRequests()
        .antMatchers("/**").permitAll()            
        // private endpoints
        .anyRequest().authenticated();

    http.addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class);

    return http.build();
}
Run Code Online (Sandbox Code Playgroud)

以下是jwtTokenFilter:

@Component
public class **JwtTokenFilter** extends OncePerRequestFilter {

    @Autowired
    private JwtTokenUtil jwtTokenUtil;
    
    @Autowired
    private JPAUserDetailService jpaUserDetailService;

    

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws ServletException, IOException {
        // Get authorization header and validate
        final String header = request.getHeader(HttpHeaders.AUTHORIZATION);
        
        if (isEmpty(header) || !header.startsWith("Bearer ")) {
            chain.doFilter(request, response);
            return;
        }

        // Get jwt token and validate
        final String token = header.split(" ")[1].trim();
        
        if (!jwtTokenUtil.validate(token)) {
                                    
            chain.doFilter(request, response);
            
            return;
        }

        // Get user identity and set it on the spring security context
        UserDetails userDetails = jpaUserDetailService.loadUserByUsername(jwtTokenUtil.getUsername(token));

        UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, (userDetails == null ? null : userDetails.getAuthorities()));

        
        authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));

        SecurityContextHolder.getContext().setAuthentication(authentication);
                
        chain.doFilter(request, response);
    }

}
Run Code Online (Sandbox Code Playgroud)

Mar*_*gio 3

在 Spring Security 6 中,默认行为是SecurityContextHolderFilter只会读取SecurityContextfromSecurityContextRepository并将其填充到SecurityContextHolder. SecurityContext如果用户SecurityContextRepository希望在请求之间保留,则现在必须显式保存SecurityContext。只需在必要时写入SecurityContextRepository(ie ) 即可消除歧义并提高性能。HttpSession

SecurityContextHolder.setContext(securityContext);
securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse);
Run Code Online (Sandbox Code Playgroud)

请参阅https://docs.spring.io/spring-security/reference/5.8/migration.html#_explicit_save_securitycontextrepository

如果这不起作用,请尝试返回到 5.x 默认值:

http
    .securityContext((securityContext) -> 
            .requireExplicitSave(false)
    )
Run Code Online (Sandbox Code Playgroud)