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