JwtGenerator: authenticationTime不能为空
就在将SpringBoot更新到4.0.6之后,我的 spring-boot-starter-oauth2-authorization-server 一直出现以下异常:
java.lang.IllegalArgumentException: authenticationTime cannot be null
at org.springframework.util.Assert.notNull(Assert.java:182)
at org.springframework.security.oauth2.server.authorization.token.JwtGenerator.getAuthenticationTime(JwtGenerator.java:237)
at org.springframework.security.oauth2.server.authorization.token.JwtGenerator.generate(JwtGenerator.java:147)
at org.springframework.security.oauth2.server.authorization.token.JwtGenerator.generate(JwtGenerator.java:66)
at org.springframework.security.oauth2.server.authorization.token.DelegatingOAuth2TokenGenerator.generate(DelegatingOAuth2TokenGenerator.java:60)
at org.springframework.security.oauth2.server.authorization.authentication.OAuth2AuthorizationCodeAuthenticationProvider.authenticate(OAuth2AuthorizationCodeAuthenticationProvider.java:274)
at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:183)
at org.springframework.security.authentication.ObservationAuthenticationManager.lambda$authenticate$1(ObservationAuthenticationManager.java:55)
at io.micrometer.observation.Observation.observe(Observation.java:634)
at org.springframework.security.authentication.ObservationAuthenticationManager.authenticate(ObservationAuthenticationManager.java:54)
at org.springframework.security.oauth2.server.authorization.web.OAuth2TokenEndpointFilter.doFilterInternal(OAuth2TokenEndpointFilter.java:170)
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:116)
要点摘要
如果你在securityContext中设置了任何 AbstractAuthenticationToken 的实例,它必须包含一个带有 issuedAt 时间的权限:
new UsernamePasswordAuthenticationToken("some name", "some credentials", List.of(
FactorGrantedAuthority.withAuthority("Some Authority")
.issuedAt(Instant.now())
.build()
));
说明
问题出在Spring Boot 4.0.6 也将 spring-boot-starter-oauth2-authorization-server 的版本更新到了 7.0.5。
在7.0.5版本中,JwtGenerator 类不再像在 7.0.4 那样从请求中获取 authenticationTime:
claimsBuilder.claim(IdTokenClaimNames.AUTH_TIME, sessionInformation.getLastRequest());
而是现在使用以下逻辑:
claimsBuilder.claim(IdTokenClaimNames.AUTH_TIME, getAuthenticationTime(context.getPrincipal()));
//...
static Date getAuthenticationTime(Authentication authentication) {
Instant authenticationTime = null;
for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) {
if (grantedAuthority instanceof FactorGrantedAuthority factorGrantedAuthority) {
if (authenticationTime == null || factorGrantedAuthority.getIssuedAt().isAfter(authenticationTime)) {
authenticationTime = factorGrantedAuthority.getIssuedAt();
}
}
}
Assert.notNull(authenticationTime, "authenticationTime cannot be null");
return Date.from(authenticationTime);
}
因此现在它试图从权限列表中读取authenticationTime,如果在某处有人手动设置了身份验证对象(因为各种自定义逻辑),这将不起作用。
简而言之,像这样的做法不再起作用:
new UsernamePasswordAuthenticationToken("some name", "some credentials", List.of());
现在它必须包含issuedAt,例如:
new UsernamePasswordAuthenticationToken("some name", "some credentials", List.of(
FactorGrantedAuthority.withAuthority("Some Authority")
.issuedAt(Instant.now())
.build()
));
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。