package com.crm.auth.security; import com.crm.base.security.DataVisibility; import com.crm.base.security.DataVisibilityContext; import org.springframework.security.core.authority.SimpleGrantedAuthority; import java.util.ArrayList; import java.util.List; import java.util.Set; /** * 权限解析结果:一次 resolve 拿齐一个用户的三份授权事实(ADR-0011)。 * *

不可变。纯取值对象——装载 {@link DataVisibilityContext} 是请求生命周期所有者 * (JWT 过滤器)的职责,本对象不产生副作用。

* * */ public final class PermissionGrant { /** Spring Security 角色 authority 前缀(hasRole('X') 实际匹配 ROLE_X) */ private static final String ROLE_PREFIX = "ROLE_"; private final DataVisibility visibility; private final Set permCodes; private final Set roleCodes; public PermissionGrant(DataVisibility visibility, Set permCodes, Set roleCodes) { this.visibility = visibility; this.permCodes = permCodes == null ? Set.of() : Set.copyOf(permCodes); this.roleCodes = roleCodes == null ? Set.of() : Set.copyOf(roleCodes); } public DataVisibility getVisibility() { return visibility; } /** 权限码并集:button 节点 perms 的去重集合,已排除停用权限点 */ public Set getPermCodes() { return permCodes; } /** 角色编码集合(原样,不带 ROLE_ 前缀约定) */ public Set getRoleCodes() { return roleCodes; } /** * 合成 Spring Security authorities:权限码原样注入;角色编码幂等归一到 ROLE_ 前缀 * (已带前缀的不重复加),使 hasAuthority / hasRole 各自按约定匹配。 * 前缀约定由本模块保证,调用方与 DB 数据无需理解它。 */ public List asAuthorities() { List authorities = new ArrayList<>(permCodes.size() + roleCodes.size()); permCodes.forEach(perm -> authorities.add(new SimpleGrantedAuthority(perm))); roleCodes.forEach(role -> authorities.add(new SimpleGrantedAuthority(normalizeRole(role)))); return List.copyOf(authorities); } private static String normalizeRole(String roleCode) { return roleCode.startsWith(ROLE_PREFIX) ? roleCode : ROLE_PREFIX + roleCode; } }