目前正在执行从 Spring Boot v2.3.5 到 v2.4.0 的升级。但是,当用户通过身份验证并实际通过FilterChain时,我遇到了设置SecurityContextHolder的问题。
有问题的代码是扩展BasicAuthenticationFilter的类的一部分,如下所示:
/**
* Perform the filter for authentication
*
* @param request The HttpServletRequest
* @param response The HttpServletResponse
* @param chain The FilterChain
* @throws IOException When the filter could not be performed
* @throws ServletException When the filter could not be performed
*/
@Override
protected void doFilterInternal(final HttpServletRequest request,
final HttpServletResponse response,
final FilterChain chain) throws IOException, ServletException {
final String header = request.getHeader(jwtConfiguration.getHeader());
if (header == null || !header.startsWith(jwtConfiguration.getTokenPrefix())) {
chain.doFilter(request, response);
return;
}
final UsernamePasswordAuthenticationToken authentication = getAuthentication(request);
if (authentication == null) {
response.setStatus(HttpStatus.UNAUTHORIZED.value());
} else {
final SecurityContext context = SecurityContextHolder.createEmptyContext();
context.setAuthentication(authentication);
SecurityContextHolder.setContext(context);
chain.doFilter(request, response); // The exception is thrown here, but only when setting the SecurityContextHolder
}
}
...
/**
* Get the UsernamePasswordAuthenticationToken from the HttpServletRequest
*
* @param request The HttpServletRequest
* @return The UsernamePasswordAuthenticationToken that was filtered from the HttpServletRequest
*/
private UsernamePasswordAuthenticationToken getAuthentication(final HttpServletRequest request) {
final String token = request.getHeader(jwtConfiguration.getHeader());
if (token != null && !token.isEmpty()) {
final UserDto user = authorizationService.getCurrentUser(token);
if (user != null) {
final Set<GrantedAuthority> grantedAuthorities = new HashSet<>();
if (user.getRoles() != null) {
for (final RoleDto role : user.getRoles()) {
if (role.getPermissions() != null) {
for (final PermissionDto permission : role.getPermissions()) {
grantedAuthorities.add(new SimpleGrantedAuthority(permission.getName()));
}
}
}
}
return new UsernamePasswordAuthenticationToken(user, null, grantedAuthorities);
}
return null;
}
return null;
}
如果不设置SecurityContextHolder,代码就可以正常工作,但不幸的是,不会设置身份验证,这不是我想要的结果,因为我想保护某些端点。
扩展WebSecurityConfigurerAdapter的类设置如下:
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(securedEnabled = true, jsr250Enabled = true, prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
private final JwtConfiguration jwtConfiguration;
private final IAuthorizationService userService;
/**
* Initialize a new WebSecurityConfiguration
*
* @param jwtConfiguration The JwtConfiguration object
* @param userService The IAuthorizationService implementation
*/
public WebSecurityConfiguration(@Autowired final JwtConfiguration jwtConfiguration,
@Autowired final IAuthorizationService userService) {
if (jwtConfiguration == null)
throw new NullPointerException("JwtConfig cannot be null!");
if (userService == null)
throw new NullPointerException("IAuthorizationService cannot be null!");
this.jwtConfiguration = jwtConfiguration;
this.userService = userService;
}
/**
* Configure the HttpSecurity
*
* @param http The HttpSecurity object
* @throws Exception When the configuration failed
*/
@Override
protected void configure(final HttpSecurity http) throws Exception {
final AuthenticationManager authenticationManager = authenticationManager();
http
.csrf().disable().cors().and()
.authorizeRequests()
.antMatchers("/authentication/**",
"/v2/api-docs",
"/configuration/ui",
"/swagger-resources/**",
"/configuration/security",
"/swagger-ui.html",
"/webjars/**")
.permitAll()
.anyRequest().authenticated()
.and()
.addFilterBefore(new JwtAuthorizationFilter(authenticationManager, jwtConfiguration, userService), JwtAuthorizationFilter.class)
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
}
}
在通过链时设置 SecurityContextHolder 时发生的异常本身如下:
java.lang.IllegalStateException:没有找到接口 org.springframework.security.core.Authentication 的主要或单个公共构造函数 - 也没有找到默认构造函数