feat: return authorization snapshot outside jwt

This commit is contained in:
2026-09-07 12:14:48 +08:00
parent a99ca36316
commit a077f828ae
5 changed files with 31 additions and 6 deletions
@@ -2,6 +2,8 @@ package com.baiyue.auth.dto;
import io.swagger.v3.oas.annotations.media.Schema;
import java.util.Set;
/**
* 认证令牌响应契约,返回访问令牌、刷新令牌及其有效期等会话信息。
*/
@@ -15,6 +17,12 @@ public record TokenResponse(
@Schema(description = "Short-lived overseas API access token; null only when overseas JWT is disabled / 海外 API 短时访问令牌;仅海外 JWT 未启用时为空",
format = "password", nullable = true) String overseasAccessToken,
@Schema(description = "Overseas access token lifetime in seconds; zero only when overseas JWT is disabled / 海外访问令牌有效秒数;仅海外 JWT 未启用时为 0",
example = "900", minimum = "0") long overseasExpiresIn
example = "900", minimum = "0") long overseasExpiresIn,
@Schema(description = "Current role snapshot returned outside JWT / JWT 外返回的当前角色快照") Set<String> roles,
@Schema(description = "Current authority snapshot returned outside JWT / JWT 外返回的当前权限快照") Set<String> authorities
) {
public TokenResponse {
roles = roles == null ? Set.of() : Set.copyOf(roles);
authorities = authorities == null ? Set.of() : Set.copyOf(authorities);
}
}
@@ -150,7 +150,8 @@ public class AuthService {
return new TokenResponse("Bearer", accessToken, properties.accessTokenTtl().toSeconds(),
rawRefresh, properties.refreshTokenTtl().toSeconds(),
overseas == null ? null : overseas.accessToken(),
overseas == null ? 0L : overseas.expiresIn());
overseas == null ? 0L : overseas.expiresIn(),
authorization.getRoles(), authorization.getPermissions());
}
@Transactional
@@ -57,8 +57,15 @@ public class OverseasTokenService {
JwtClaimsSet claims = claimsBuilder.build();
String token = encoder.encode(JwtEncoderParameters.from(
JwsHeader.with(SignatureAlgorithm.RS256).keyId(properties.currentKid()).build(), claims)).getTokenValue();
return new OverseasTokenResponse("Bearer", token, properties.accessTokenTtl().toSeconds());
return new OverseasTokenResponse("Bearer", token, properties.accessTokenTtl().toSeconds(),
authorization.getRoles(), authorization.getPermissions());
}
public record OverseasTokenResponse(String tokenType, String accessToken, long expiresIn) { }
public record OverseasTokenResponse(String tokenType, String accessToken, long expiresIn,
java.util.Set<String> roles, java.util.Set<String> authorities) {
public OverseasTokenResponse {
roles = roles == null ? java.util.Set.of() : java.util.Set.copyOf(roles);
authorities = authorities == null ? java.util.Set.of() : java.util.Set.copyOf(authorities);
}
}
}
@@ -72,7 +72,8 @@ class AuthServiceSmallJwtTest {
when(jwtEncoder.encode(any())).thenReturn(encoded);
when(encoded.getTokenValue()).thenReturn("small-token");
when(overseasTokenService.issue(account, snapshot)).thenReturn(
new OverseasTokenService.OverseasTokenResponse("Bearer", "overseas-token", 900));
new OverseasTokenService.OverseasTokenResponse("Bearer", "overseas-token", 900,
snapshot.getRoles(), snapshot.getPermissions()));
var response = service.login(new LoginRequest("operator", "secret"));
@@ -98,6 +99,8 @@ class AuthServiceSmallJwtTest {
verify(overseasTokenService).issue(account, snapshot);
assertThat(response.overseasAccessToken()).isEqualTo("overseas-token");
assertThat(response.overseasExpiresIn()).isEqualTo(900);
assertThat(response.roles()).containsExactly("OVERSEAS_WAREHOUSE_PDA_OPERATOR");
assertThat(response.authorities()).containsExactly("platform:order:list");
}
@Test
@@ -162,7 +165,8 @@ class AuthServiceSmallJwtTest {
when(jwtEncoder.encode(any())).thenReturn(encoded);
when(encoded.getTokenValue()).thenReturn("domestic-refreshed");
when(overseasTokenService.issue(account, snapshot)).thenReturn(
new OverseasTokenService.OverseasTokenResponse("Bearer", "overseas-refreshed", 900));
new OverseasTokenService.OverseasTokenResponse("Bearer", "overseas-refreshed", 900,
snapshot.getRoles(), snapshot.getPermissions()));
var response = service.refresh("refresh-old");
@@ -173,6 +177,8 @@ class AuthServiceSmallJwtTest {
assertThat(response.refreshExpiresIn()).isEqualTo(604800);
assertThat(response.overseasAccessToken()).isEqualTo("overseas-refreshed");
assertThat(response.overseasExpiresIn()).isEqualTo(900);
assertThat(response.roles()).containsExactly("MERCHANT_ADMIN");
assertThat(response.authorities()).containsExactly("merchant:order:list");
verify(tokenSessionStore).consume("refresh-old");
verify(tokenSessionStore).store(anyString(), org.mockito.ArgumentMatchers.eq(52L),
org.mockito.ArgumentMatchers.eq(Set.of("MERCHANT_ADMIN")),
@@ -82,6 +82,9 @@ class OverseasTokenServiceTest {
.doesNotContainKeys("roles", "authorities", "permissions", "userId", "tenantId", "appCode",
"permissionVersion");
assertThat(response.expiresIn()).isEqualTo(900);
assertThat(response.roles()).containsExactly("OVERSEAS_WAREHOUSE_PDA_OPERATOR");
assertThat(response.authorities()).containsExactlyInAnyOrder(authority, merchantAuthority,
merchantCrossBorderAuthority, lastlegAuthority, financeAuthority, domesticAuthority);
}
@Test