组织权限Java微服务后端架构实战

1. 架构概述

组织权限系统是企业管理平台的核心模块,需要支持多层级组织架构管理、用户权限分配、权限验证和数据权限过滤。本篇文章将深入讲解如何基于Java微服务架构实现一个高性能、高可用、灵活可扩展的组织权限管理系统,支持根组织、运营商、片区、站点、运维点等多层级组织架构,以及用户与组织节点的权限关联。

1.1 系统架构图

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
组织权限系统架构
├── 组织架构管理
│ ├── 根(组织)
│ ├── 运营商A
│ ├── 运营商B
│ │ ├── 站点1, 站点2, 站点3, 站点4, 站点5, 运维点
│ │ └── 片区1, 片区2, 片区3
│ │ ├── 片区1 → 站点1, 站点2, 站点3
│ │ ├── 片区2 → 站点4, 站点5
│ │ └── 片区3
│ └── 组织树查询、组织节点管理

├── 用户权限管理
│ ├── 运营商B用户 → 所属: 站点1, 站点2
│ ├── 运维A → 所属: 站点3, 站点4, 站点5, 运维点, 片区1
│ └── 运维B → 所属: 片区2

├── 权限验证服务
│ ├── 用户组织权限验证
│ ├── 数据权限过滤
│ └── 组织节点访问控制

└── 数据权限过滤
├── 查询数据时过滤组织节点
├── 根据用户所属组织节点过滤
└── 支持组织树递归查询

1.2 核心组件

  • 组织服务(Organization Service):负责组织架构管理、组织树查询、组织节点CRUD
  • 权限服务(Permission Service):负责用户权限分配、权限验证、数据权限过滤
  • 用户服务(User Service):负责用户管理、用户组织关联
  • 网关服务(Gateway Service):负责请求接入、权限拦截、数据权限过滤
  • 数据库(MySQL):持久化组织架构、用户权限、组织节点关系
  • 缓存(Redis):缓存组织树、用户权限、权限验证结果
  • 分布式锁(Redisson):保证组织节点操作的并发安全

2. 组织服务实现

2.1 组织服务控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
/**
* 组织服务控制器
* 提供组织架构管理接口
*/
@RestController
@RequestMapping("/api/organization")
@Slf4j
public class OrganizationController {

@Autowired
private OrganizationService organizationService;

@Autowired
private PermissionService permissionService;

/**
* 创建组织节点
* 流程:权限验证 → 创建组织节点 → 更新组织树缓存 → 返回结果
*/
@PostMapping("/node/create")
public Result<OrganizationNode> createOrganizationNode(
@RequestBody @Valid CreateOrganizationNodeRequest request,
@RequestHeader("Authorization") String token) {

try {
// 1. 权限验证
UserInfo userInfo = permissionService.getUserInfoFromToken(token);
if (!permissionService.hasPermission(userInfo.getUserId(), "organization:create")) {
return Result.error("无权限创建组织节点");
}

// 2. 创建组织节点
OrganizationNode node = organizationService.createNode(request);

return Result.success(node);

} catch (Exception e) {
log.error("创建组织节点失败: error={}", e.getMessage(), e);
return Result.error("创建组织节点失败: " + e.getMessage());
}
}

/**
* 更新组织节点
*/
@PutMapping("/node/{nodeId}")
public Result<OrganizationNode> updateOrganizationNode(
@PathVariable Long nodeId,
@RequestBody @Valid UpdateOrganizationNodeRequest request,
@RequestHeader("Authorization") String token) {

try {
// 1. 权限验证
UserInfo userInfo = permissionService.getUserInfoFromToken(token);
if (!permissionService.hasNodePermission(userInfo.getUserId(), nodeId, "organization:update")) {
return Result.error("无权限更新该组织节点");
}

// 2. 更新组织节点
OrganizationNode node = organizationService.updateNode(nodeId, request);

return Result.success(node);

} catch (Exception e) {
log.error("更新组织节点失败: nodeId={}, error={}",
nodeId, e.getMessage(), e);
return Result.error("更新组织节点失败: " + e.getMessage());
}
}

/**
* 删除组织节点
*/
@DeleteMapping("/node/{nodeId}")
public Result<Void> deleteOrganizationNode(
@PathVariable Long nodeId,
@RequestHeader("Authorization") String token) {

try {
// 1. 权限验证
UserInfo userInfo = permissionService.getUserInfoFromToken(token);
if (!permissionService.hasNodePermission(userInfo.getUserId(), nodeId, "organization:delete")) {
return Result.error("无权限删除该组织节点");
}

// 2. 删除组织节点
organizationService.deleteNode(nodeId);

return Result.success();

} catch (Exception e) {
log.error("删除组织节点失败: nodeId={}, error={}",
nodeId, e.getMessage(), e);
return Result.error("删除组织节点失败: " + e.getMessage());
}
}

/**
* 获取组织树
* 流程:根据用户权限过滤组织树 → 返回组织树
*/
@GetMapping("/tree")
public Result<OrganizationTree> getOrganizationTree(
@RequestHeader("Authorization") String token,
@RequestParam(required = false) Long rootNodeId) {

try {
// 1. 获取用户信息
UserInfo userInfo = permissionService.getUserInfoFromToken(token);

// 2. 获取用户可访问的组织节点
Set<Long> accessibleNodeIds = permissionService.getAccessibleNodeIds(userInfo.getUserId());

// 3. 获取组织树(根据权限过滤)
OrganizationTree tree = organizationService.getOrganizationTree(rootNodeId, accessibleNodeIds);

return Result.success(tree);

} catch (Exception e) {
log.error("获取组织树失败: error={}", e.getMessage(), e);
return Result.error("获取组织树失败: " + e.getMessage());
}
}

/**
* 获取组织节点详情
*/
@GetMapping("/node/{nodeId}")
public Result<OrganizationNode> getOrganizationNode(
@PathVariable Long nodeId,
@RequestHeader("Authorization") String token) {

try {
// 1. 权限验证
UserInfo userInfo = permissionService.getUserInfoFromToken(token);
if (!permissionService.hasNodePermission(userInfo.getUserId(), nodeId, "organization:view")) {
return Result.error("无权限查看该组织节点");
}

// 2. 获取组织节点
OrganizationNode node = organizationService.getNodeById(nodeId);

return Result.success(node);

} catch (Exception e) {
log.error("获取组织节点失败: nodeId={}, error={}",
nodeId, e.getMessage(), e);
return Result.error("获取组织节点失败: " + e.getMessage());
}
}

/**
* 获取组织节点的子节点列表
*/
@GetMapping("/node/{nodeId}/children")
public Result<List<OrganizationNode>> getChildNodes(
@PathVariable Long nodeId,
@RequestHeader("Authorization") String token) {

try {
// 1. 权限验证
UserInfo userInfo = permissionService.getUserInfoFromToken(token);
if (!permissionService.hasNodePermission(userInfo.getUserId(), nodeId, "organization:view")) {
return Result.error("无权限查看该组织节点");
}

// 2. 获取子节点列表
List<OrganizationNode> children = organizationService.getChildNodes(nodeId);

// 3. 根据用户权限过滤
Set<Long> accessibleNodeIds = permissionService.getAccessibleNodeIds(userInfo.getUserId());
children = children.stream()
.filter(node -> accessibleNodeIds.contains(node.getId()))
.collect(Collectors.toList());

return Result.success(children);

} catch (Exception e) {
log.error("获取子节点列表失败: nodeId={}, error={}",
nodeId, e.getMessage(), e);
return Result.error("获取子节点列表失败: " + e.getMessage());
}
}
}

2.2 组织服务实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
/**
* 组织服务实现
* 负责组织架构管理
*/
@Service
@Slf4j
public class OrganizationService {

@Autowired
private OrganizationMapper organizationMapper;

@Autowired
private RedisTemplate<String, Object> redisTemplate;

@Autowired
private RedissonClient redissonClient;

/**
* 创建组织节点
*/
@Transactional(rollbackFor = Exception.class)
public OrganizationNode createNode(CreateOrganizationNodeRequest request) {
// 1. 获取分布式锁
RLock lock = redissonClient.getLock("org:node:create:" + request.getParentId());
try {
lock.lock(10, TimeUnit.SECONDS);

// 2. 验证父节点是否存在
if (request.getParentId() != null && request.getParentId() > 0) {
OrganizationNode parentNode = organizationMapper.selectById(request.getParentId());
if (parentNode == null) {
throw new BusinessException("父节点不存在");
}
}

// 3. 创建组织节点
OrganizationNode node = new OrganizationNode();
node.setName(request.getName());
node.setCode(request.getCode());
node.setType(request.getType());
node.setParentId(request.getParentId());
node.setLevel(calculateLevel(request.getParentId()));
node.setPath(calculatePath(request.getParentId()));
node.setSortOrder(request.getSortOrder());
node.setStatus("ACTIVE");
node.setCreateTime(LocalDateTime.now());
node.setUpdateTime(LocalDateTime.now());

organizationMapper.insert(node);

// 4. 更新组织树缓存
clearOrganizationTreeCache();

log.info("创建组织节点成功: nodeId={}, name={}, parentId={}",
node.getId(), node.getName(), node.getParentId());

return node;

} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}

/**
* 更新组织节点
*/
@Transactional(rollbackFor = Exception.class)
public OrganizationNode updateNode(Long nodeId, UpdateOrganizationNodeRequest request) {
// 1. 获取分布式锁
RLock lock = redissonClient.getLock("org:node:update:" + nodeId);
try {
lock.lock(10, TimeUnit.SECONDS);

// 2. 获取组织节点
OrganizationNode node = organizationMapper.selectById(nodeId);
if (node == null) {
throw new BusinessException("组织节点不存在");
}

// 3. 更新组织节点
if (request.getName() != null) {
node.setName(request.getName());
}
if (request.getCode() != null) {
node.setCode(request.getCode());
}
if (request.getSortOrder() != null) {
node.setSortOrder(request.getSortOrder());
}
node.setUpdateTime(LocalDateTime.now());

organizationMapper.updateById(node);

// 4. 更新组织树缓存
clearOrganizationTreeCache();

log.info("更新组织节点成功: nodeId={}, name={}", nodeId, node.getName());

return node;

} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}

/**
* 删除组织节点
*/
@Transactional(rollbackFor = Exception.class)
public void deleteNode(Long nodeId) {
// 1. 获取分布式锁
RLock lock = redissonClient.getLock("org:node:delete:" + nodeId);
try {
lock.lock(10, TimeUnit.SECONDS);

// 2. 检查是否有子节点
List<OrganizationNode> children = organizationMapper.selectList(
new LambdaQueryWrapper<OrganizationNode>()
.eq(OrganizationNode::getParentId, nodeId));
if (!children.isEmpty()) {
throw new BusinessException("存在子节点,无法删除");
}

// 3. 检查是否有用户关联
long userCount = checkUserAssociation(nodeId);
if (userCount > 0) {
throw new BusinessException("存在用户关联,无法删除");
}

// 4. 删除组织节点
organizationMapper.deleteById(nodeId);

// 5. 更新组织树缓存
clearOrganizationTreeCache();

log.info("删除组织节点成功: nodeId={}", nodeId);

} finally {
if (lock.isHeldByCurrentThread()) {
lock.unlock();
}
}
}

/**
* 获取组织树
*/
public OrganizationTree getOrganizationTree(Long rootNodeId, Set<Long> accessibleNodeIds) {
try {
// 1. 从缓存获取
String cacheKey = "org:tree:" + (rootNodeId != null ? rootNodeId : "root");
OrganizationTree cachedTree = (OrganizationTree) redisTemplate.opsForValue().get(cacheKey);
if (cachedTree != null && accessibleNodeIds == null) {
return cachedTree;
}

// 2. 从数据库构建组织树
OrganizationTree tree = buildOrganizationTree(rootNodeId);

// 3. 根据权限过滤组织树
if (accessibleNodeIds != null && !accessibleNodeIds.isEmpty()) {
tree = filterTreeByPermission(tree, accessibleNodeIds);
}

// 4. 缓存组织树(如果不需要权限过滤)
if (accessibleNodeIds == null) {
redisTemplate.opsForValue().set(cacheKey, tree, 1, TimeUnit.HOURS);
}

return tree;

} catch (Exception e) {
log.error("获取组织树失败: rootNodeId={}, error={}",
rootNodeId, e.getMessage(), e);
throw new BusinessException("获取组织树失败: " + e.getMessage());
}
}

/**
* 构建组织树
*/
private OrganizationTree buildOrganizationTree(Long rootNodeId) {
// 1. 获取根节点
OrganizationNode rootNode;
if (rootNodeId != null) {
rootNode = organizationMapper.selectById(rootNodeId);
} else {
rootNode = organizationMapper.selectOne(
new LambdaQueryWrapper<OrganizationNode>()
.isNull(OrganizationNode::getParentId)
.last("LIMIT 1"));
}

if (rootNode == null) {
return new OrganizationTree();
}

// 2. 递归构建树
OrganizationTree tree = new OrganizationTree();
tree.setNode(rootNode);
tree.setChildren(buildChildrenTree(rootNode.getId()));

return tree;
}

/**
* 递归构建子节点树
*/
private List<OrganizationTree> buildChildrenTree(Long parentId) {
List<OrganizationNode> children = organizationMapper.selectList(
new LambdaQueryWrapper<OrganizationNode>()
.eq(OrganizationNode::getParentId, parentId)
.orderByAsc(OrganizationNode::getSortOrder));

List<OrganizationTree> childrenTree = new ArrayList<>();
for (OrganizationNode child : children) {
OrganizationTree tree = new OrganizationTree();
tree.setNode(child);
tree.setChildren(buildChildrenTree(child.getId()));
childrenTree.add(tree);
}

return childrenTree;
}

/**
* 根据权限过滤组织树
*/
private OrganizationTree filterTreeByPermission(OrganizationTree tree, Set<Long> accessibleNodeIds) {
if (tree == null || tree.getNode() == null) {
return null;
}

Long nodeId = tree.getNode().getId();

// 如果当前节点不可访问,返回null
if (!accessibleNodeIds.contains(nodeId)) {
return null;
}

// 过滤子节点
List<OrganizationTree> filteredChildren = new ArrayList<>();
if (tree.getChildren() != null) {
for (OrganizationTree child : tree.getChildren()) {
OrganizationTree filteredChild = filterTreeByPermission(child, accessibleNodeIds);
if (filteredChild != null) {
filteredChildren.add(filteredChild);
}
}
}

OrganizationTree filteredTree = new OrganizationTree();
filteredTree.setNode(tree.getNode());
filteredTree.setChildren(filteredChildren);

return filteredTree;
}

/**
* 获取组织节点
*/
public OrganizationNode getNodeById(Long nodeId) {
OrganizationNode node = organizationMapper.selectById(nodeId);
if (node == null) {
throw new BusinessException("组织节点不存在");
}
return node;
}

/**
* 获取子节点列表
*/
public List<OrganizationNode> getChildNodes(Long parentId) {
return organizationMapper.selectList(
new LambdaQueryWrapper<OrganizationNode>()
.eq(OrganizationNode::getParentId, parentId)
.orderByAsc(OrganizationNode::getSortOrder));
}

/**
* 计算层级
*/
private Integer calculateLevel(Long parentId) {
if (parentId == null || parentId == 0) {
return 1;
}

OrganizationNode parent = organizationMapper.selectById(parentId);
if (parent == null) {
return 1;
}

return parent.getLevel() + 1;
}

/**
* 计算路径
*/
private String calculatePath(Long parentId) {
if (parentId == null || parentId == 0) {
return "/";
}

OrganizationNode parent = organizationMapper.selectById(parentId);
if (parent == null) {
return "/";
}

return parent.getPath() + parentId + "/";
}

/**
* 检查用户关联
*/
private long checkUserAssociation(Long nodeId) {
// 实际实现中查询用户组织关联表
return 0;
}

/**
* 清除组织树缓存
*/
private void clearOrganizationTreeCache() {
Set<String> keys = redisTemplate.keys("org:tree:*");
if (keys != null && !keys.isEmpty()) {
redisTemplate.delete(keys);
}
}
}

3. 权限服务实现

3.1 权限服务控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
/**
* 权限服务控制器
* 提供用户权限管理接口
*/
@RestController
@RequestMapping("/api/permission")
@Slf4j
public class PermissionController {

@Autowired
private PermissionService permissionService;

/**
* 分配用户组织权限
* 流程:权限验证 → 分配用户组织节点 → 更新权限缓存 → 返回结果
*/
@PostMapping("/user/organization/assign")
public Result<Void> assignUserOrganizationPermission(
@RequestBody @Valid AssignUserOrganizationRequest request,
@RequestHeader("Authorization") String token) {

try {
// 1. 权限验证
UserInfo userInfo = permissionService.getUserInfoFromToken(token);
if (!permissionService.hasPermission(userInfo.getUserId(), "permission:assign")) {
return Result.error("无权限分配用户组织权限");
}

// 2. 分配用户组织权限
permissionService.assignUserOrganizationPermission(
request.getUserId(), request.getNodeIds());

return Result.success();

} catch (Exception e) {
log.error("分配用户组织权限失败: error={}", e.getMessage(), e);
return Result.error("分配用户组织权限失败: " + e.getMessage());
}
}

/**
* 获取用户组织权限
*/
@GetMapping("/user/{userId}/organization")
public Result<List<OrganizationNode>> getUserOrganizationPermission(
@PathVariable Long userId,
@RequestHeader("Authorization") String token) {

try {
// 1. 权限验证
UserInfo currentUser = permissionService.getUserInfoFromToken(token);
if (!currentUser.getUserId().equals(userId) &&
!permissionService.hasPermission(currentUser.getUserId(), "permission:view")) {
return Result.error("无权限查看用户组织权限");
}

// 2. 获取用户组织权限
List<OrganizationNode> nodes = permissionService.getUserOrganizationNodes(userId);

return Result.success(nodes);

} catch (Exception e) {
log.error("获取用户组织权限失败: userId={}, error={}",
userId, e.getMessage(), e);
return Result.error("获取用户组织权限失败: " + e.getMessage());
}
}

/**
* 验证用户是否有组织节点权限
*/
@PostMapping("/user/organization/verify")
public Result<Boolean> verifyUserOrganizationPermission(
@RequestBody @Valid VerifyPermissionRequest request,
@RequestHeader("Authorization") String token) {

try {
// 1. 获取用户信息
UserInfo userInfo = permissionService.getUserInfoFromToken(token);

// 2. 验证权限
boolean hasPermission = permissionService.hasNodePermission(
userInfo.getUserId(), request.getNodeId(), request.getPermission());

return Result.success(hasPermission);

} catch (Exception e) {
log.error("验证用户组织权限失败: error={}", e.getMessage(), e);
return Result.error("验证用户组织权限失败: " + e.getMessage());
}
}

/**
* 获取用户可访问的组织节点ID集合
*/
@GetMapping("/user/{userId}/accessible-nodes")
public Result<Set<Long>> getAccessibleNodeIds(
@PathVariable Long userId,
@RequestHeader("Authorization") String token) {

try {
// 1. 权限验证
UserInfo currentUser = permissionService.getUserInfoFromToken(token);
if (!currentUser.getUserId().equals(userId) &&
!permissionService.hasPermission(currentUser.getUserId(), "permission:view")) {
return Result.error("无权限查看用户可访问节点");
}

// 2. 获取可访问节点ID集合
Set<Long> nodeIds = permissionService.getAccessibleNodeIds(userId);

return Result.success(nodeIds);

} catch (Exception e) {
log.error("获取用户可访问节点失败: userId={}, error={}",
userId, e.getMessage(), e);
return Result.error("获取用户可访问节点失败: " + e.getMessage());
}
}
}

3.2 权限服务实现

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
/**
* 权限服务实现
* 负责用户权限管理、权限验证、数据权限过滤
*/
@Service
@Slf4j
public class PermissionService {

@Autowired
private UserOrganizationMapper userOrganizationMapper;

@Autowired
private OrganizationMapper organizationMapper;

@Autowired
private RedisTemplate<String, Object> redisTemplate;

@Autowired
private JwtTokenUtil jwtTokenUtil;

/**
* 分配用户组织权限
*/
@Transactional(rollbackFor = Exception.class)
public void assignUserOrganizationPermission(Long userId, List<Long> nodeIds) {
try {
// 1. 删除原有权限
userOrganizationMapper.delete(
new LambdaQueryWrapper<UserOrganization>()
.eq(UserOrganization::getUserId, userId));

// 2. 分配新权限
if (nodeIds != null && !nodeIds.isEmpty()) {
for (Long nodeId : nodeIds) {
// 验证组织节点是否存在
OrganizationNode node = organizationMapper.selectById(nodeId);
if (node == null) {
throw new BusinessException("组织节点不存在: nodeId=" + nodeId);
}

// 创建用户组织关联
UserOrganization userOrg = new UserOrganization();
userOrg.setUserId(userId);
userOrg.setNodeId(nodeId);
userOrg.setCreateTime(LocalDateTime.now());
userOrganizationMapper.insert(userOrg);
}
}

// 3. 清除权限缓存
clearUserPermissionCache(userId);

log.info("分配用户组织权限成功: userId={}, nodeIds={}", userId, nodeIds);

} catch (Exception e) {
log.error("分配用户组织权限失败: userId={}, nodeIds={}, error={}",
userId, nodeIds, e.getMessage(), e);
throw new BusinessException("分配用户组织权限失败: " + e.getMessage());
}
}

/**
* 获取用户组织节点列表
*/
public List<OrganizationNode> getUserOrganizationNodes(Long userId) {
try {
// 1. 从缓存获取
String cacheKey = "user:org:nodes:" + userId;
List<OrganizationNode> cachedNodes = (List<OrganizationNode>)
redisTemplate.opsForValue().get(cacheKey);
if (cachedNodes != null) {
return cachedNodes;
}

// 2. 从数据库查询
List<UserOrganization> userOrgs = userOrganizationMapper.selectList(
new LambdaQueryWrapper<UserOrganization>()
.eq(UserOrganization::getUserId, userId));

List<OrganizationNode> nodes = new ArrayList<>();
for (UserOrganization userOrg : userOrgs) {
OrganizationNode node = organizationMapper.selectById(userOrg.getNodeId());
if (node != null) {
nodes.add(node);
}
}

// 3. 缓存结果
redisTemplate.opsForValue().set(cacheKey, nodes, 1, TimeUnit.HOURS);

return nodes;

} catch (Exception e) {
log.error("获取用户组织节点失败: userId={}, error={}",
userId, e.getMessage(), e);
throw new BusinessException("获取用户组织节点失败: " + e.getMessage());
}
}

/**
* 获取用户可访问的组织节点ID集合(包括子节点)
*/
public Set<Long> getAccessibleNodeIds(Long userId) {
try {
// 1. 从缓存获取
String cacheKey = "user:org:accessible:nodeIds:" + userId;
Set<Long> cachedNodeIds = (Set<Long>) redisTemplate.opsForValue().get(cacheKey);
if (cachedNodeIds != null) {
return cachedNodeIds;
}

// 2. 获取用户直接关联的组织节点
List<OrganizationNode> userNodes = getUserOrganizationNodes(userId);
Set<Long> nodeIds = new HashSet<>();
for (OrganizationNode node : userNodes) {
nodeIds.add(node.getId());
// 递归获取所有子节点
Set<Long> childNodeIds = getAllChildNodeIds(node.getId());
nodeIds.addAll(childNodeIds);
}

// 3. 缓存结果
redisTemplate.opsForValue().set(cacheKey, nodeIds, 1, TimeUnit.HOURS);

return nodeIds;

} catch (Exception e) {
log.error("获取用户可访问节点ID集合失败: userId={}, error={}",
userId, e.getMessage(), e);
throw new BusinessException("获取用户可访问节点ID集合失败: " + e.getMessage());
}
}

/**
* 递归获取所有子节点ID
*/
private Set<Long> getAllChildNodeIds(Long parentId) {
Set<Long> nodeIds = new HashSet<>();

List<OrganizationNode> children = organizationMapper.selectList(
new LambdaQueryWrapper<OrganizationNode>()
.eq(OrganizationNode::getParentId, parentId));

for (OrganizationNode child : children) {
nodeIds.add(child.getId());
// 递归获取子节点的子节点
Set<Long> grandChildNodeIds = getAllChildNodeIds(child.getId());
nodeIds.addAll(grandChildNodeIds);
}

return nodeIds;
}

/**
* 验证用户是否有组织节点权限
*/
public boolean hasNodePermission(Long userId, Long nodeId, String permission) {
try {
// 1. 获取用户可访问的节点ID集合
Set<Long> accessibleNodeIds = getAccessibleNodeIds(userId);

// 2. 检查节点是否在可访问集合中
if (!accessibleNodeIds.contains(nodeId)) {
return false;
}

// 3. 检查具体权限(如果需要)
// 这里可以根据permission参数进行更细粒度的权限检查

return true;

} catch (Exception e) {
log.error("验证用户组织节点权限失败: userId={}, nodeId={}, permission={}, error={}",
userId, nodeId, permission, e.getMessage(), e);
return false;
}
}

/**
* 验证用户是否有权限
*/
public boolean hasPermission(Long userId, String permission) {
// 实际实现中查询用户角色权限表
// 这里简化处理
return true;
}

/**
* 从Token获取用户信息
*/
public UserInfo getUserInfoFromToken(String token) {
try {
String userId = jwtTokenUtil.getUserIdFromToken(token);
String username = jwtTokenUtil.getUsernameFromToken(token);

UserInfo userInfo = new UserInfo();
userInfo.setUserId(Long.parseLong(userId));
userInfo.setUsername(username);

return userInfo;

} catch (Exception e) {
log.error("从Token获取用户信息失败: error={}", e.getMessage(), e);
throw new BusinessException("Token无效");
}
}

/**
* 数据权限过滤:根据用户组织权限过滤数据
*/
public <T extends OrganizationData> List<T> filterByOrganizationPermission(
Long userId, List<T> dataList) {

try {
// 1. 获取用户可访问的节点ID集合
Set<Long> accessibleNodeIds = getAccessibleNodeIds(userId);

// 2. 过滤数据
return dataList.stream()
.filter(data -> accessibleNodeIds.contains(data.getNodeId()))
.collect(Collectors.toList());

} catch (Exception e) {
log.error("数据权限过滤失败: userId={}, error={}",
userId, e.getMessage(), e);
return Collections.emptyList();
}
}

/**
* 数据权限过滤:构建SQL条件
*/
public String buildOrganizationFilterCondition(Long userId) {
try {
// 1. 获取用户可访问的节点ID集合
Set<Long> accessibleNodeIds = getAccessibleNodeIds(userId);

if (accessibleNodeIds.isEmpty()) {
return "1=0"; // 无权限,返回空结果
}

// 2. 构建IN条件
String nodeIds = accessibleNodeIds.stream()
.map(String::valueOf)
.collect(Collectors.joining(","));

return "node_id IN (" + nodeIds + ")";

} catch (Exception e) {
log.error("构建组织过滤条件失败: userId={}, error={}",
userId, e.getMessage(), e);
return "1=0";
}
}

/**
* 清除用户权限缓存
*/
private void clearUserPermissionCache(Long userId) {
Set<String> keys = new HashSet<>();
keys.add("user:org:nodes:" + userId);
keys.add("user:org:accessible:nodeIds:" + userId);

redisTemplate.delete(keys);
}
}

4. 数据模型定义

4.1 组织节点实体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
/**
* 组织节点实体
*/
@Data
@TableName("t_organization_node")
public class OrganizationNode {

/**
* 节点ID
*/
@TableId(type = IdType.AUTO)
private Long id;

/**
* 节点名称
*/
private String name;

/**
* 节点编码
*/
private String code;

/**
* 节点类型:ROOT-根组织, OPERATOR-运营商, AREA-片区, SITE-站点, OMPOINT-运维点
*/
private String type;

/**
* 父节点ID
*/
private Long parentId;

/**
* 层级
*/
private Integer level;

/**
* 路径
*/
private String path;

/**
* 排序
*/
private Integer sortOrder;

/**
* 状态:ACTIVE-激活, INACTIVE-停用
*/
private String status;

/**
* 创建时间
*/
private LocalDateTime createTime;

/**
* 更新时间
*/
private LocalDateTime updateTime;
}

4.2 用户组织关联实体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
/**
* 用户组织关联实体
*/
@Data
@TableName("t_user_organization")
public class UserOrganization {

/**
* 关联ID
*/
@TableId(type = IdType.AUTO)
private Long id;

/**
* 用户ID
*/
private Long userId;

/**
* 组织节点ID
*/
private Long nodeId;

/**
* 创建时间
*/
private LocalDateTime createTime;
}

4.3 组织树实体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 组织树实体
*/
@Data
public class OrganizationTree {

/**
* 组织节点
*/
private OrganizationNode node;

/**
* 子节点列表
*/
private List<OrganizationTree> children;
}

4.4 用户信息实体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* 用户信息实体
*/
@Data
public class UserInfo {

/**
* 用户ID
*/
private Long userId;

/**
* 用户名
*/
private String username;
}

5. 数据库设计

5.1 组织节点表

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
CREATE TABLE `t_organization_node` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '节点ID',
`name` VARCHAR(128) NOT NULL COMMENT '节点名称',
`code` VARCHAR(64) DEFAULT NULL COMMENT '节点编码',
`type` VARCHAR(32) NOT NULL COMMENT '节点类型:ROOT-根组织, OPERATOR-运营商, AREA-片区, SITE-站点, OMPOINT-运维点',
`parent_id` BIGINT(20) DEFAULT NULL COMMENT '父节点ID',
`level` INT(11) NOT NULL COMMENT '层级',
`path` VARCHAR(512) DEFAULT NULL COMMENT '路径',
`sort_order` INT(11) DEFAULT 0 COMMENT '排序',
`status` VARCHAR(32) NOT NULL DEFAULT 'ACTIVE' COMMENT '状态:ACTIVE-激活, INACTIVE-停用',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
`update_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_code` (`code`),
KEY `idx_parent_id` (`parent_id`),
KEY `idx_type` (`type`),
KEY `idx_status` (`status`),
KEY `idx_path` (`path`(255))
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='组织节点表';

5.2 用户组织关联表

1
2
3
4
5
6
7
8
9
10
CREATE TABLE `t_user_organization` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT COMMENT '关联ID',
`user_id` BIGINT(20) NOT NULL COMMENT '用户ID',
`node_id` BIGINT(20) NOT NULL COMMENT '组织节点ID',
`create_time` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
PRIMARY KEY (`id`),
UNIQUE KEY `uk_user_node` (`user_id`, `node_id`),
KEY `idx_user_id` (`user_id`),
KEY `idx_node_id` (`node_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='用户组织关联表';

6. 数据权限过滤拦截器

6.1 MyBatis拦截器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
/**
* 数据权限过滤拦截器
* 自动在SQL中添加组织权限过滤条件
*/
@Intercepts({
@Signature(type = Executor.class, method = "update", args = {MappedStatement.class, Object.class}),
@Signature(type = Executor.class, method = "query", args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class})
})
@Component
@Slf4j
public class OrganizationPermissionInterceptor implements Interceptor {

@Autowired
private PermissionService permissionService;

@Autowired
private JwtTokenUtil jwtTokenUtil;

@Override
public Object intercept(Invocation invocation) throws Throwable {
try {
// 1. 获取当前用户ID
Long userId = getCurrentUserId();
if (userId == null) {
return invocation.proceed();
}

// 2. 获取MappedStatement
MappedStatement ms = (MappedStatement) invocation.getArgs()[0];

// 3. 检查是否需要权限过滤
if (!needPermissionFilter(ms)) {
return invocation.proceed();
}

// 4. 获取用户可访问的节点ID集合
Set<Long> accessibleNodeIds = permissionService.getAccessibleNodeIds(userId);

if (accessibleNodeIds.isEmpty()) {
// 无权限,返回空结果
return getEmptyResult(invocation, ms);
}

// 5. 修改SQL,添加组织权限过滤条件
BoundSql boundSql = ms.getBoundSql(invocation.getArgs()[1]);
String originalSql = boundSql.getSql();
String filteredSql = addOrganizationFilter(originalSql, accessibleNodeIds);

// 6. 创建新的BoundSql
BoundSql newBoundSql = new BoundSql(ms.getConfiguration(), filteredSql,
boundSql.getParameterMappings(), boundSql.getParameterObject());

// 7. 创建新的MappedStatement
MappedStatement newMs = copyFromMappedStatement(ms, new BoundSqlSqlSource(newBoundSql));
invocation.getArgs()[0] = newMs;

return invocation.proceed();

} catch (Exception e) {
log.error("数据权限过滤拦截失败: error={}", e.getMessage(), e);
return invocation.proceed();
}
}

/**
* 获取当前用户ID
*/
private Long getCurrentUserId() {
try {
HttpServletRequest request = ((ServletRequestAttributes)
RequestContextHolder.getRequestAttributes()).getRequest();
String token = request.getHeader("Authorization");
if (token == null || token.isEmpty()) {
return null;
}

String userId = jwtTokenUtil.getUserIdFromToken(token);
return Long.parseLong(userId);

} catch (Exception e) {
return null;
}
}

/**
* 检查是否需要权限过滤
*/
private boolean needPermissionFilter(MappedStatement ms) {
// 检查方法名或SQL ID是否包含特定标识
String sqlId = ms.getId();
return sqlId.contains("Organization") || sqlId.contains("Site") ||
sqlId.contains("Device") || sqlId.contains("Order");
}

/**
* 添加组织权限过滤条件
*/
private String addOrganizationFilter(String sql, Set<Long> nodeIds) {
String nodeIdsStr = nodeIds.stream()
.map(String::valueOf)
.collect(Collectors.joining(","));

// 在WHERE子句中添加条件
String condition = "node_id IN (" + nodeIdsStr + ")";

if (sql.toUpperCase().contains("WHERE")) {
return sql + " AND " + condition;
} else {
return sql + " WHERE " + condition;
}
}

/**
* 获取空结果
*/
private Object getEmptyResult(Invocation invocation, MappedStatement ms) {
if (invocation.getMethod().getName().equals("query")) {
return new ArrayList<>();
}
return 0;
}

/**
* 复制MappedStatement
*/
private MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource) {
MappedStatement.Builder builder = new MappedStatement.Builder(
ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType());

builder.resource(ms.getResource());
builder.fetchSize(ms.getFetchSize());
builder.timeout(ms.getTimeout());
builder.statementType(ms.getStatementType());
builder.keyGenerator(ms.getKeyGenerator());
builder.keyProperty(ms.getKeyProperties() == null ? null :
String.join(",", ms.getKeyProperties()));
builder.keyColumn(ms.getKeyColumns() == null ? null :
String.join(",", ms.getKeyColumns()));
builder.databaseId(ms.getDatabaseId());
builder.lang(ms.getLang());
builder.resultOrdered(ms.isResultOrdered());
builder.resultSets(ms.getResultSets() == null ? null :
String.join(",", ms.getResultSets()));
builder.resultMaps(ms.getResultMaps());
builder.resultSetType(ms.getResultSetType());
builder.flushCacheRequired(ms.isFlushCacheRequired());
builder.useCache(ms.isUseCache());
builder.cache(ms.getCache());

return builder.build();
}

@Override
public Object plugin(Object target) {
return Plugin.wrap(target, this);
}

@Override
public void setProperties(Properties properties) {
// 设置属性
}
}

/**
* BoundSql SqlSource
*/
class BoundSqlSqlSource implements SqlSource {
private BoundSql boundSql;

public BoundSqlSqlSource(BoundSql boundSql) {
this.boundSql = boundSql;
}

@Override
public BoundSql getBoundSql(Object parameterObject) {
return boundSql;
}
}

7. 配置类

7.1 MyBatis配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* MyBatis配置
*/
@Configuration
public class MyBatisConfig {

@Autowired
private OrganizationPermissionInterceptor permissionInterceptor;

@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
factory.setDataSource(dataSource);

// 添加拦截器
factory.setPlugins(new Interceptor[]{permissionInterceptor});

return factory.getObject();
}
}

7.2 Redis配置

1
2
3
4
5
6
7
8
9
10
11
12
13
# application.yml
spring:
redis:
host: localhost
port: 6379
password:
database: 0
timeout: 3000
lettuce:
pool:
max-active: 20
max-idle: 10
min-idle: 5

8. 性能优化策略

8.1 组织树缓存优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
* 组织树缓存服务
*/
@Service
@Slf4j
public class OrganizationTreeCacheService {

@Autowired
private RedisTemplate<String, Object> redisTemplate;

@Autowired
private OrganizationService organizationService;

/**
* 获取组织树(带缓存)
*/
public OrganizationTree getOrganizationTreeWithCache(Long rootNodeId) {
String cacheKey = "org:tree:" + (rootNodeId != null ? rootNodeId : "root");

// 从缓存获取
OrganizationTree tree = (OrganizationTree) redisTemplate.opsForValue().get(cacheKey);
if (tree != null) {
return tree;
}

// 从数据库构建
tree = organizationService.getOrganizationTree(rootNodeId, null);

// 缓存1小时
redisTemplate.opsForValue().set(cacheKey, tree, 1, TimeUnit.HOURS);

return tree;
}

/**
* 清除组织树缓存
*/
public void clearOrganizationTreeCache(Long nodeId) {
// 清除所有相关缓存
Set<String> keys = redisTemplate.keys("org:tree:*");
if (keys != null && !keys.isEmpty()) {
redisTemplate.delete(keys);
}
}
}

8.2 权限缓存优化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/**
* 权限缓存服务
*/
@Service
@Slf4j
public class PermissionCacheService {

@Autowired
private RedisTemplate<String, Object> redisTemplate;

@Autowired
private PermissionService permissionService;

/**
* 获取用户可访问节点ID集合(带缓存)
*/
public Set<Long> getAccessibleNodeIdsWithCache(Long userId) {
String cacheKey = "user:org:accessible:nodeIds:" + userId;

// 从缓存获取
Set<Long> nodeIds = (Set<Long>) redisTemplate.opsForValue().get(cacheKey);
if (nodeIds != null) {
return nodeIds;
}

// 从数据库查询
nodeIds = permissionService.getAccessibleNodeIds(userId);

// 缓存1小时
redisTemplate.opsForValue().set(cacheKey, nodeIds, 1, TimeUnit.HOURS);

return nodeIds;
}
}

9. 监控告警

9.1 业务指标监控

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
/**
* 组织权限监控指标
*/
@Component
@Slf4j
public class OrganizationPermissionMetrics {

@Autowired
private MeterRegistry meterRegistry;

/**
* 记录组织节点创建
*/
public void recordNodeCreate(String nodeType) {
Counter.builder("organization.node.create.total")
.tag("node_type", nodeType)
.register(meterRegistry)
.increment();
}

/**
* 记录权限验证
*/
public void recordPermissionVerify(boolean success) {
Counter.builder("permission.verify.total")
.tag("success", String.valueOf(success))
.register(meterRegistry)
.increment();
}
}

10. 总结

本文深入讲解了组织权限的Java微服务后端架构实战,涵盖了以下核心内容:

  1. 组织架构管理:支持多层级组织架构(根组织、运营商、片区、站点、运维点),实现组织树的构建、查询、更新、删除
  2. 用户权限分配:支持用户与组织节点的关联,实现用户组织权限的分配和管理
  3. 权限验证服务:实现用户组织节点权限的验证,支持细粒度权限控制
  4. 数据权限过滤:通过MyBatis拦截器自动在SQL中添加组织权限过滤条件,实现数据权限的自动过滤
  5. 组织树查询:支持根据用户权限过滤组织树,只返回用户可访问的组织节点
  6. 权限缓存优化:通过Redis缓存组织树和用户权限,提升查询性能
  7. 分布式锁:使用Redisson保证组织节点操作的并发安全
  8. 性能优化:通过缓存、批量查询等优化系统性能
  9. 监控告警:通过业务指标监控保障系统稳定运行

通过本文的学习,读者可以掌握如何基于Java微服务架构实现一个高性能、高可用、灵活可扩展的组织权限管理系统,为实际项目的权限管理提供参考和指导。