我们正在尝试将我们的应用程序从Java 8 + Sping Boot 2迁移到Java 17 + Spring Boot 3。几乎所有的事情都与我们用@PreAuthorize注解的API调用分开工作。
下面是我们配置的简化版本:
@Configuration
@RequiredArgsConstructor
@EnableWebSecurity(debug = true)
@EnableMethodSecurity
public class SecurityConfiguration {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
http.csrf().disable();
http.cors();
http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeHttpRequests()
.requestMatchers("/api/**")
.authenticated()
.and()
.oauth2ResourceServer()
.jwt()
.jwtAuthenticationConverter( new JwtAuthenticationConverter() );
return http.build();
}
@Bean
public JwtDecoder jwtDecoder(OAuth2ResourceServerProperties properties) {
NimbusJwtDecoder jwtDecoder = NimbusJwtDecoder.withJwkSetUri(
properties.getJwt().getJwkSetUri()).build();
return jwtDecoder;
}
}
class JwtAuthenticationConverter implements Converter<Jwt, AbstractAuthenticationToken> {
@Override
public AbstractAuthenticationToken convert(Jwt jwt) {
return new JwtAuthenticationToken(jwt, new JwtAuthoritiesConverter().convert(jwt));
}
}
class JwtAuthoritiesConverter implements Converter<Jwt, Collection<GrantedAuthority>> {
@Override
public Collection<GrantedAuthority> convert(Jwt jwt) {
Collection<GrantedAuthority> grantedAuthorities = new ArrayList<GrantedAuthority>();
grantedAuthorities.add(new SimpleGrantedAuthority("SOME_AUTHORITY"));
return grantedAuthorities;
}
}
还有一个示例方法:
@PreAuthorize("hasAnyAuthority('SOME_AUTHORITY')")
@GetMapping("/someObjects") APIResponse<SomeObject> testMethod(JwtAuthenticationToken principal){
List<GrantedAuthority> principalAuthorities= principal.getAuthorities().stream().collect(Collectors.toList());
log.info("Authorities: " + principalAuthorities.toString());
List<GrantedAuthority> authorities = SecurityContextHolder.getContext().getAuthentication().getAuthorities().stream().collect(Collectors.toList());
log.info("Security Context" + authorities.toString());
return APIResponse.singleton(new SomeObject());
}
取出PreAuthorize注解允许我们访问该方法并打印GrantedAuthorizations,这似乎是正确的:
2023-06-28T09:48:27,618 INFO SomeController::testMethod(223):当局:[SOME_AUTHORITY] 2023-06-28T09:48:27,618 INFO SomeController:安全上下文[SOME_AUTHORITY]
然而,将其添加回会导致返回HTTP 401。当启用trace时,我们还会看到这些日志:
2023-06-28T11:27:13,166 DEBUG o.s.o.s.r.w.a. BearerTokenAuthenticationFilter::doFilterInternal(143):将SecurityContextHolder设置为JwtAuthenticationToken [Principal=org.springframework.security.oauth2.jwt.Jwt@eb761cc7,Credentials=[PROTECTTED],Authenticated=true,Details=WebAuthenticationDetails [RemoteIpAddress=0:0:0:0:0:0:0:1,SessionId=null],授予的权限=[SOME_AUTHORITY]]
...
2023-06-28T11:27:13,174 TRACE o.s.s.w.a.ExceptionTranslationFilter::handleAuthenticationException(184):由于身份验证失败,发送到身份验证入口点org.springframework.security.authentication.AuthenticationCredentialsNotFoundException:在SecurityContext中找不到身份验证对象
我们能查到什么进一步追查吗?同样的代码在我们的旧代码库中运行得很好(使用WebSecurityConfigureAdapter)。
编辑:如果我们设置了以下内容,则“预授权”似乎适用于我们:
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_THREADLOCAL);
而不是:
SecurityContextHolder.setStrategyName(SecurityContextHolder.MODE_INHERITABLETHREADLOCAL);
任何解释都将非常感谢。
1条答案
按热度按时间rhfm7lfc1#
在配置文件中添加以下注解: