package com.baiyue.common.security; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.AutoConfiguration; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.security.oauth2.jwt.JwtDecoder; import org.springframework.security.oauth2.jwt.JwtValidators; import org.springframework.security.oauth2.jwt.NimbusJwtDecoder; import org.springframework.security.oauth2.jwt.JwtClaimValidator; import org.springframework.security.oauth2.core.DelegatingOAuth2TokenValidator; import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; import java.util.List; /** 所有业务服务通过可轮换 JWKS 验证 RS256,会话由共享 Redis 校验。 */ @AutoConfiguration(before = BaiyueSecurityAutoConfiguration.class) public class JwksJwtDecoderAutoConfiguration { @Bean @ConditionalOnMissingBean(JwtDecoder.class) JwtDecoder jwksJwtDecoder(@Value("${baiyue.security.jwk-set-uri:${JWT_JWKS_URI:http://auth-service:9100/api/auth/.well-known/jwks.json}}") String uri, @Value("${baiyue.security.issuer:auth-service}") String issuer, @Value("${baiyue.security.audience:lastleg-api}") String audience) { // Fetch and cache JWKS on token verification, so startup does not depend on Auth availability. NimbusJwtDecoder decoder = NimbusJwtDecoder.withJwkSetUri(uri) .jwsAlgorithm(SignatureAlgorithm.RS256).build(); decoder.setJwtValidator(new DelegatingOAuth2TokenValidator<>( JwtValidators.createDefaultWithIssuer(issuer), new JwtClaimValidator>("aud", values -> values != null && values.contains(audience)))); return decoder; } }