diff --git a/auth/src/main/java/com/baiyue/auth/config/AuthSecurityConfig.java b/auth/src/main/java/com/baiyue/auth/config/AuthSecurityConfig.java index d4a1960e7..7362715cc 100644 --- a/auth/src/main/java/com/baiyue/auth/config/AuthSecurityConfig.java +++ b/auth/src/main/java/com/baiyue/auth/config/AuthSecurityConfig.java @@ -1,8 +1,6 @@ package com.baiyue.auth.config; -import com.nimbusds.jose.jwk.JWKSet; -import com.nimbusds.jose.jwk.RSAKey; -import com.nimbusds.jose.jwk.source.ImmutableJWKSet; +import com.nimbusds.jose.jwk.source.ImmutableSecret; import com.baiyue.common.security.JwtAuthenticationFilter; import org.springframework.boot.context.properties.EnableConfigurationProperties; import org.springframework.context.annotation.Bean; @@ -33,7 +31,6 @@ public class AuthSecurityConfig { "/api/auth/refresh", "/api/auth/logout", "/api/auth/impersonations/exchange", - "/api/auth/.well-known/jwks.json", "/actuator/health", "/v3/api-docs/**", "/swagger-ui/**", @@ -45,19 +42,9 @@ public class AuthSecurityConfig { @Bean JwtEncoder jwtEncoder(AuthSecurityProperties properties) { - try { - JWKSet set = JWKSet.parse(properties.rsaJwkSet()); - RSAKey current = set.getKeyByKeyId(properties.currentKid()) instanceof RSAKey rsa ? rsa : null; - if (current == null || !current.isPrivate()) { - throw new IllegalStateException("current-kid 必须指向一把包含私钥的 RSA 签名密钥"); - } - if (set.getKeys().stream().anyMatch(jwk -> !(jwk instanceof RSAKey))) { - throw new IllegalStateException("RSA JWK Set 只能包含 RSA 密钥"); - } - return new NimbusJwtEncoder(new ImmutableJWKSet<>(set)); - } catch (java.text.ParseException exception) { - throw new IllegalStateException("RSA JWK Set配置无效", exception); - } + byte[] secret = properties.jwtSecret().getBytes(StandardCharsets.UTF_8); + if (secret.length < 32) throw new IllegalStateException("JWT_SECRET 至少需要 32 字节"); + return new NimbusJwtEncoder(new ImmutableSecret<>(secret)); } @Bean diff --git a/auth/src/main/java/com/baiyue/auth/config/AuthSecurityProperties.java b/auth/src/main/java/com/baiyue/auth/config/AuthSecurityProperties.java index 3a58bb6ce..5b9f00a1c 100644 --- a/auth/src/main/java/com/baiyue/auth/config/AuthSecurityProperties.java +++ b/auth/src/main/java/com/baiyue/auth/config/AuthSecurityProperties.java @@ -9,7 +9,6 @@ import java.time.Duration; */ @ConfigurationProperties(prefix = "baiyue.security") public record AuthSecurityProperties(String jwtSecret, String issuer, String audience, - String rsaJwkSet, String currentKid, Duration accessTokenTtl, Duration refreshTokenTtl, int maxLoginFailures, Duration lockDuration) { } diff --git a/auth/src/main/java/com/baiyue/auth/controller/JwksController.java b/auth/src/main/java/com/baiyue/auth/controller/JwksController.java deleted file mode 100644 index bd2246c57..000000000 --- a/auth/src/main/java/com/baiyue/auth/controller/JwksController.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.baiyue.auth.controller; - -import com.baiyue.auth.config.AuthSecurityProperties; -import com.nimbusds.jose.jwk.JWKSet; -import org.springframework.http.CacheControl; -import org.springframework.http.ResponseEntity; -import org.springframework.web.bind.annotation.GetMapping; -import org.springframework.web.bind.annotation.RestController; - -import java.util.Map; -import java.util.concurrent.TimeUnit; - -/** 仅发布 RSA 公钥;轮换期配置当前与上一把公钥。 */ -@RestController -public class JwksController { - private final AuthSecurityProperties properties; - public JwksController(AuthSecurityProperties properties) { this.properties = properties; } - - @GetMapping("/api/auth/.well-known/jwks.json") - public ResponseEntity> jwks() throws Exception { - JWKSet publicSet = JWKSet.parse(properties.rsaJwkSet()).toPublicJWKSet(); - return ResponseEntity.ok() - .cacheControl(CacheControl.maxAge(5, TimeUnit.MINUTES).cachePublic()) - .body(publicSet.toJSONObject()); - } -} diff --git a/auth/src/main/java/com/baiyue/auth/service/AuthService.java b/auth/src/main/java/com/baiyue/auth/service/AuthService.java index 2d3125afd..f9be566f8 100644 --- a/auth/src/main/java/com/baiyue/auth/service/AuthService.java +++ b/auth/src/main/java/com/baiyue/auth/service/AuthService.java @@ -16,7 +16,7 @@ import com.baiyue.common.core.exception.BizException; import jakarta.annotation.Resource; import org.springframework.security.crypto.password.PasswordEncoder; -import org.springframework.security.oauth2.jose.jws.SignatureAlgorithm; +import org.springframework.security.oauth2.jose.jws.MacAlgorithm; import org.springframework.security.oauth2.jwt.JwtClaimsSet; import org.springframework.security.oauth2.jwt.JwtEncoder; import org.springframework.security.oauth2.jwt.JwtEncoderParameters; @@ -198,7 +198,7 @@ public class AuthService { public record ImpersonationTokenResponse(String tokenType, String accessToken, long expiresIn) { } private JwsHeader signingHeader() { - return JwsHeader.with(SignatureAlgorithm.RS256).keyId(properties.currentKid()).build(); + return JwsHeader.with(MacAlgorithm.HS256).build(); } private static BizException invalidCredentials() { diff --git a/auth/src/main/resources/application.yml b/auth/src/main/resources/application.yml index 3b3e03682..126c6e6c3 100644 --- a/auth/src/main/resources/application.yml +++ b/auth/src/main/resources/application.yml @@ -31,8 +31,6 @@ spring: encode: UTF-8 baiyue.security: jwt-secret: ${JWT_SECRET:change-me-to-at-least-32-bytes-long-before-start} - rsa-jwk-set: ${JWT_RSA_JWK_SET:} - current-kid: ${JWT_CURRENT_KID:} internal-service-token: ${INTERNAL_SERVICE_TOKEN:change-me-to-an-internal-token-at-least-32-bytes-long} token-key-prefix: ${REDIS_TOKEN_KEY_PREFIX:baiyue:auth} issuer: ${JWT_ISSUER:auth-service} diff --git a/auth/src/test/java/com/baiyue/auth/service/AuthServiceSmallJwtTest.java b/auth/src/test/java/com/baiyue/auth/service/AuthServiceSmallJwtTest.java index ad6fda064..517d0f459 100644 --- a/auth/src/test/java/com/baiyue/auth/service/AuthServiceSmallJwtTest.java +++ b/auth/src/test/java/com/baiyue/auth/service/AuthServiceSmallJwtTest.java @@ -12,6 +12,7 @@ import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.security.oauth2.jose.jws.MacAlgorithm; import org.springframework.security.oauth2.jwt.Jwt; import org.springframework.security.oauth2.jwt.JwtEncoder; import org.springframework.security.oauth2.jwt.JwtEncoderParameters; @@ -39,7 +40,7 @@ class AuthServiceSmallJwtTest { static class TestConfig { @Bean AuthSecurityProperties properties() { - return new AuthSecurityProperties("unused", "auth-service", "lastleg-api", "{}", "current-2026-08", + return new AuthSecurityProperties("unused", "auth-service", "lastleg-api", Duration.ofMinutes(30), Duration.ofDays(7), 5, Duration.ofMinutes(10)); } @@ -82,7 +83,8 @@ class AuthServiceSmallJwtTest { .containsEntry("membership_id", 84L) .doesNotContainKeys("permissions", "scope"); assertThat(jwt.getValue().getClaims().getAudience()).containsExactly("lastleg-api"); - assertThat(jwt.getValue().getJwsHeader().getKeyId()).isEqualTo("current-2026-08"); + assertThat(jwt.getValue().getJwsHeader().getAlgorithm()).isEqualTo(MacAlgorithm.HS256); + assertThat(jwt.getValue().getJwsHeader().getKeyId()).isNull(); verify(tokenSessionStore).store(any(), org.mockito.ArgumentMatchers.eq(42L), org.mockito.ArgumentMatchers.eq(Set.of("PLATFORM_ADMIN")), org.mockito.ArgumentMatchers.eq(Set.of("platform:order:list")), any(), diff --git a/config/nacos/cn/auth-service.yml b/config/nacos/cn/auth-service.yml index 5166142e8..fd913df2e 100644 --- a/config/nacos/cn/auth-service.yml +++ b/config/nacos/cn/auth-service.yml @@ -7,6 +7,5 @@ spring: baiyue: security: audience: ${JWT_AUDIENCE:lastleg-api} - current-kid: ${JWT_CURRENT_KID:} access-token-ttl: ${ACCESS_TOKEN_TTL:15m} refresh-token-ttl: ${REFRESH_TOKEN_TTL:7d}