Home > Enterprise >  Spring Security: An Authentication object was not found in the SecurityContext
Spring Security: An Authentication object was not found in the SecurityContext

Time:11-08

The following config (filterChain) works fine in SpringBoot-2.7.5, but after I tried to test it in SpringBoot-3.0.0-RC1, it is not working and shows the following message, anything I need to change if want to migrate to Spring-Boot-3.0.0. Thanks.

{ "timestamp": 1667794247614, "status": 401, "error": "Unauthorized", "message": "An Authentication object was not found in the 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();
}

The following is the 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);
    }

}

CodePudding user response:

In Spring Security 6, the default behavior is that the SecurityContextHolderFilter will only read the SecurityContext from SecurityContextRepository and populate it in the SecurityContextHolder. Users now must explicitly save the SecurityContext with the SecurityContextRepository if they want the SecurityContext to persist between requests. This removes ambiguity and improves performance by only requiring writing to the SecurityContextRepository (i.e. HttpSession) when it is necessary.

SecurityContextHolder.setContext(securityContext);
securityContextRepository.saveContext(securityContext, httpServletRequest, httpServletResponse);

See https://docs.spring.io/spring-security/reference/5.8/migration.html#_explicit_save_securitycontextrepository

CodePudding user response:

I changed some codes as following, but still not working.

    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));

    
    SecurityContextImpl scix = new SecurityContextImpl(authentication);
    
    SecurityContextHolder.setContext(scix);
    
    
    
    RequestAttributeSecurityContextRepository securityContextRepository = new RequestAttributeSecurityContextRepository();
    
    securityContextRepository.saveContext(scix, request, response);
    
    
    chain.doFilter(request, response);
}

and the configas following:

@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
    
    
    
    http.cors().and().csrf().disable()
        .exceptionHandling().authenticationEntryPoint(jwtAuthenticationProvider)
        .and()
        .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
        .and()
        .authorizeHttpRequests((requests) -> requests
                .requestMatchers("/swagger-ui", "/rest-api-docs").permitAll()                   
                .anyRequest().authenticated()
        )
        //.requestMatchers("/**").permitAll()
        //.antMatchers("/v2/api-docs", "/v2/logs", "/swagger-resources/**", "/swagger-ui.html", "/webjars/**", "/swagger/**").permitAll() //swagger
        .addFilterBefore(jwtTokenFilter, UsernamePasswordAuthenticationFilter.class)
        .securityContext((securityContext) -> 
            securityContext.securityContextRepository(new RequestAttributeSecurityContextRepository())
            .requireExplicitSave(true)
        )
        ;

    
    
    
    return http.build();
}
  • Related