本文目录导读:

设计一个Java分布式数据角色API,核心在于将数据访问权限与用户身份解耦,并确保在分布式环境下的一致性、高性能和可扩展性。
下面我提供一个从核心概念、架构设计到具体代码实现的分层方案。
核心设计原则
- 数据隔离:角色控制数据可见范围(仅自己、本部门、全局)。
- 动态性:角色、权限、数据范围支持运行时变更,无需重启服务。
- 去中心化:API 不含业务逻辑,仅做校验与数据过滤。
- 可组合:支持角色叠加(用户有多个角色时取权限并集或最大范围)。
核心概念模型
- User(用户) :访问主体。
- Role(角色) :权限集合的载体(如:管理员、数据录入员、审计员)。
- Permission(权限) :操作数据的原子能力(如:READ、WRITE、DELETE)。
- DataScope(数据范围) :可被操作的数据边界(如:公司ID、部门ID、用户ID)。
- RoleAssignment(角色分配) :用户与角色的绑定关系,含生效时间、来源系统等。
架构分层
[API网关] -> [业务服务] -> [分布式权限引擎] -> [数据服务]
- 业务服务:调用权限服务获取当前用户的角色与数据范围。
- 分布式权限引擎:核心组件,负责鉴权与数据过滤条件生成。
- 数据服务:接收包含权限过滤条件的请求,执行数据查询。
API 设计(RESTful + RPC)
1 角色与权限管理 API(面向管理员 / 权限中心)
// 1. 创建角色
POST /api/v1/roles
{
"roleName": "部门经理",
"description": "管理本部门数据",
"permissions": ["READ", "WRITE"],
"dataScope": "DEPARTMENT" // SELF | DEPARTMENT | COMPANY
}
// 2. 为用户分配角色
POST /api/v1/role-assignments
{
"userId": "user-123",
"roleId": "role-dept-manager",
"effectiveDate": "2024-01-01T00:00:00Z",
"source": "HR_SYSTEM" // 来源系统,便于分布式追溯
}
// 3. 获取用户的所有角色与权限(核心接口)
GET /api/v1/users/{userId}/roles-and-permissions
// 返回示例
{
"userId": "user-123",
"roles": [
{
"roleId": "role-dept-manager",
"permissions": ["READ", "WRITE"],
"dataScope": "DEPARTMENT",
"context": { "departmentId": "dept-456" } // 数据范围的上下文值
}
],
"effectivePermissions": ["READ", "WRITE"],
"maxDataScope": "DEPARTMENT"
}
2 数据访问控制 API(面向业务代码)
这部分不是直接暴露给用户,而是业务服务在查询数据时调用。
// 1. 校验当前用户是否有权操作特定数据
POST /api/v1/authorize
{
"userId": "user-123",
"permission": "WRITE",
"resource": "ORDER",
"resourceId": "order-789"
}
// 返回:200 OK 或 403 Forbidden
// 2. 获取当前用户的数据过滤条件(核心引擎接口)
POST /api/v1/data-filters
{
"userId": "user-123",
"resource": "SALES_REPORT"
}
// 返回:
{
"type": "IN",
"field": "department_id",
"values": ["dept-456", "dept-789"]
}
// 业务服务直接拼接到SQL或ES查询中
分布式实现关键点
1 数据库设计(支持多活)
-- 核心表(跨数据中心共享) CREATE TABLE roles ( role_id VARCHAR(64) PRIMARY KEY, role_name VARCHAR(128), permissions JSON, -- ["READ","WRITE"] data_scope VARCHAR(32), -- SELF, DEPARTMENT, COMPANY updated_at BIGINT ); CREATE TABLE role_assignments ( id BIGINT AUTO_INCREMENT PRIMARY KEY, user_id VARCHAR(64), role_id VARCHAR(64), effective_date TIMESTAMP, source VARCHAR(32), -- 来源系统标识 UNIQUE KEY uk_user_role (user_id, role_id, effective_date) );
2 缓存更新策略(万级 QPS 场景)
- 本地 + Redis 二级缓存:
- 一级缓存(Caffeine/Guava):本地内存,过期时间 10s。
- 二级缓存(Redis):分布式共享,过期时间 5min。
- 更新时:使用 Redis Pub/Sub 或消息队列广播角色变更事件,各节点订阅后清除本地缓存。
// 伪代码:获取用户角色信息
public RoleVO getRolesAndPermissions(String userId) {
// 1. 先查一级缓存(本地)
RoleVO localCache = localCache.get(userId);
if (localCache != null) return localCache;
// 2. 查二级缓存(Redis)
RoleVO redisCache = redis.get("role:" + userId);
if (redisCache != null) {
localCache.put(userId, redisCache, 10, TimeUnit.SECONDS);
return redisCache;
}
// 3. 查数据库(并写入缓存)
RoleVO dbResult = roleService.queryFromDB(userId);
redis.set("role:" + userId, dbResult, 5, TimeUnit.MINUTES);
localCache.put(userId, dbResult, 10, TimeUnit.SECONDS);
return dbResult;
}
3 高性能数据过滤(大数据量场景)
尽量不下推数据范围到应用层,而是生成可下推到数据库或搜索引擎的过滤条件。
对于 SQL 数据库:
// 生成 WHERE 条件片段
String filter = "department_id IN ('dept-456','dept-789') AND created_by = 'user-123'";
// 附加到业务查询SQL后
String fullSQL = "SELECT * FROM orders WHERE status = 'ACTIVE' AND " + filter;
对于 Elasticsearch:
// 生成 BoolQueryBuilder
BoolQueryBuilder filterBuilder = QueryBuilders.boolQuery()
.must(currentUser.getEffectiveDataScope().match("department_id"));
4 分布式事务与一致性
- 最终一致性:角色变更通过消息队列异步同步到所有数据中心。
- 冲突检测:使用乐观锁(version 字段)处理并发角色分配。
- 读时校验:即使缓存延迟,业务服务在操作关键数据时,强制调用鉴权接口实时校验。
// 写操作前的强制鉴权(不依赖缓存)
public void updateOrder(Order order, UserContext currentUser) {
// 实时鉴权
AuthorizationResult result = permissionEngine.authorize(
currentUser.getUserId(), "WRITE", "ORDER", order.getId()
);
if (!result.isAllowed()) {
throw new ForbiddenException("权限不足");
}
// 执行更新...
}
完整代码示例(核心接口)
// 1. 定义接口
public interface RoleApiService {
RoleVO getRolesAndPermissions(String userId);
AuthorizationResult authorize(String userId, String permission, String resource, String resourceId);
DataFilterVO getDataFilter(String userId, String resource);
}
// 2. 数据结构
public class RoleVO {
private List<Role> roles;
private List<String> effectivePermissions;
private DataScope maxDataScope;
}
public class DataFilterVO {
private String type; // IN, EQUAL, NESTED
private String field;
private List<String> values;
private DataFilterVO nestedFilter;
}
// 3. 实现(Spring Boot)
@Service
public class RoleApiServiceImpl implements RoleApiService {
@Autowired
private RedisTemplate<String, RoleVO> redis;
@Override
public RoleVO getRolesAndPermissions(String userId) {
// 1. 本地缓存
// 2. Redis 缓存
// 3. 数据库查询
// 4. 组装角色、权限、数据范围
}
@Override
public AuthorizationResult authorize(String userId, String permission,
String resource, String resourceId) {
// 1. 获取用户角色(从上述方法)
// 2. 检查权限是否包含 permission
// 3. 检查数据范围是否覆盖该 resourceId
// 4. 返回允许/拒绝
}
@Override
public DataFilterVO getDataFilter(String userId, String resource) {
// 1. 获取用户的数据范围
// 2. 生成该资源对应的过滤条件
// 3. 返回可下推到数据层的 Filter
}
}
总结与建议
- 不要过度抽象:如果业务只有两种数据范围(本人 / 全部),无需复杂的角色模型。
- 性能优先:鉴权操作必须在 5ms 内完成,尽量走缓存,避免查库。
- 可观测性:权限检查必须有日志和监控,便于排查“为什么无法访问”。
- 渐进式演变:可以从简单的 RBAC 开始,逐步引入数据范围、属性权限(ABAC)。
这个设计可以在微服务、多数据中心、高并发的分布式环境中稳定运行,并且具备良好的扩展性,如果你有具体的业务场景(如 SaaS 多租户、金融风控),可以在此基础上进行定制。