90 lines
3.7 KiB
Java
90 lines
3.7 KiB
Java
package com.baiyue.common.security;
|
|
|
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
|
import org.springframework.security.oauth2.jwt.Jwt;
|
|
|
|
import java.util.Collection;
|
|
import java.util.LinkedHashSet;
|
|
import java.util.List;
|
|
import java.util.Set;
|
|
|
|
/**
|
|
* JWT 声明映射器,将令牌中的用户、租户、端类型和权限声明转换为认证主体与授权集合。
|
|
*/
|
|
public class JwtClaimsMapper {
|
|
public BaiyueJwtAuthenticationToken map(Jwt jwt) {
|
|
return map(jwt, null);
|
|
}
|
|
|
|
public BaiyueJwtAuthenticationToken map(Jwt jwt, AccessTokenSession session) {
|
|
Set<String> permissions = new LinkedHashSet<>();
|
|
if (session != null) {
|
|
permissions.addAll(session.permissions());
|
|
addRoles(permissions, session.roles());
|
|
}
|
|
|
|
String appCode = firstNonBlank(jwt.getClaimAsString("appCode"), jwt.getClaimAsString("app_code"));
|
|
if (appCode != null && !appCode.isBlank()) {
|
|
permissions.add("APP_" + appCode.toUpperCase(java.util.Locale.ROOT));
|
|
}
|
|
String username = firstNonBlank(jwt.getClaimAsString("username"),
|
|
jwt.getClaimAsString("preferred_username"), jwt.getSubject());
|
|
Long userId = longClaim(jwt, "userId");
|
|
if (userId == null) userId = longClaim(jwt, "user_id");
|
|
AuthenticatedUser user = new AuthenticatedUser(
|
|
userId == null ? longValue(jwt.getSubject()) : userId,
|
|
longClaimEither(jwt, "tenantId", "tenant_id"),
|
|
longClaim(jwt, "operator_tenant_id"),
|
|
longClaim(jwt, "membership_id"),
|
|
username,
|
|
appCode,
|
|
jwt.getClaimAsString("client_type"),
|
|
permissions,
|
|
Boolean.TRUE.equals(jwt.getClaim("impersonated")),
|
|
longClaim(jwt, "actor_user_id"),
|
|
longClaim(jwt, "actor_membership_id"),
|
|
Boolean.TRUE.equals(jwt.getClaim("password_change_required")));
|
|
List<SimpleGrantedAuthority> authorities = permissions.stream()
|
|
.map(SimpleGrantedAuthority::new).toList();
|
|
return new BaiyueJwtAuthenticationToken(user, jwt.getTokenValue(), authorities);
|
|
}
|
|
|
|
private void addClaimValues(Set<String> target, Object value) {
|
|
if (value instanceof Collection<?> collection) {
|
|
collection.stream().map(Object::toString).filter(s -> !s.isBlank()).forEach(target::add);
|
|
} else if (value instanceof String text) {
|
|
for (String item : text.split("[ ,]+")) {
|
|
if (!item.isBlank()) target.add(item);
|
|
}
|
|
}
|
|
}
|
|
|
|
private void addRoles(Set<String> target, Object value) {
|
|
Set<String> roles = new LinkedHashSet<>();
|
|
addClaimValues(roles, value);
|
|
roles.stream().map(role -> role.startsWith("ROLE_") ? role : "ROLE_" + role).forEach(target::add);
|
|
}
|
|
|
|
private Long longValue(String value) {
|
|
if (value == null || value.isBlank()) return null;
|
|
try { return Long.valueOf(value); }
|
|
catch (NumberFormatException ignored) { return null; }
|
|
}
|
|
|
|
private Long longClaim(Jwt jwt, String name) {
|
|
Object value = jwt.getClaims().get(name);
|
|
if (value instanceof Number number) return number.longValue();
|
|
if (value instanceof String text) return longValue(text);
|
|
return null;
|
|
}
|
|
private Long longClaimEither(Jwt jwt, String first, String second) {
|
|
Long value = longClaim(jwt, first);
|
|
return value == null ? longClaim(jwt, second) : value;
|
|
}
|
|
|
|
private String firstNonBlank(String... values) {
|
|
for (String value : values) if (value != null && !value.isBlank()) return value;
|
|
return "unknown";
|
|
}
|
|
}
|