《Spring Security 权限控制通关指南:pmhub代码实战》
·
1. 🔐 Spring Security 权限控制详解
1.1. 知识点讲解(通俗版)
想象一下,你进入一家高级俱乐部:
- 门口保安(Security Filter) - 检查你的会员卡(Token验证)
- VIP区域管理员(@PreAuthorize) - 检查你是否有权限进入特定区域
- 普通区域 - 所有会员都可以进入
- SVIP区域 - 只有 SVIP会员才能进入
- 总统套房 - 只有顶级会员才能进入
在PmHub项目中,@PreAuthorize 就是这个"区域管理员",它会在方法执行之前检查用户是否有相应的权限。
1.2. 核心概念(通俗版)
用公司门禁系统来类比:
- 员工卡(Token) - 每个员工有一张卡,卡里记录了:
-
- 你是谁(用户信息)
- 你能进哪些房间(权限列表)
- 门禁规则(@PreAuthorize) - 每个房间门口有个读卡器:
-
- "project:manage:add" = 只有有"项目管理-新增"权限的人能进
- "system:user:edit" = 只有有"系统管理-用户编辑"权限的人能进
- 权限管理员(PermissionService) - 负责检查你的卡是否有权限
1.3. 代码流程详解
1.3.1. 第一步:配置启用权限控制
在 SecurityConfig.java 中:
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
这个注解就像开启全公司的门禁系统,prePostEnabled = true 表示启用 @PreAuthorize 和 @PostAuthorize 注解。
12.3.2. 第二步:注册权限检查服务
@Service("ss") // ← 注意这个名字 "ss"
public class PermissionService {
public boolean hasPermi(String permission) {
// 获取当前登录用户
LoginUser loginUser = SecurityUtils.getLoginUser();
// 检查用户的权限列表中是否包含所需权限
return hasPermissions(loginUser.getPermissions(), permission);
}
}
为什么叫 "ss"?
- "ss" 是 Spring Security 的缩写
- 这个Bean名称会在SpEL表达式中使用
1.3.3. 第三步:Controller中使用权限注解
@PreAuthorize("@ss.hasPermi('project:manage:add')")
@PostMapping("/add")
public AjaxResult add(@RequestBody Project project) {
projectService.saveProject(project);
return AjaxResult.success();
}
这个注解的含义:
@PreAuthorize- 在方法执行之前进行权限检查@ss- 调用名为 "ss" 的Bean(即PermissionService).hasPermi('project:manage:add')- 调用hasPermi方法,传入权限字符串
1.3.4. 第四步:权限检查流程
当一个请求到达时:
1. 用户登录 → 获得Token
↓
2. Token中包含用户信息和权限列表
例如:["project:manage:add", "project:manage:edit", "system:user:list"]
↓
3. 用户访问 /project/add 接口
↓
4. Spring Security拦截请求
↓
5. 执行 @PreAuthorize("@ss.hasPermi('project:manage:add')")
↓
6. PermissionService.hasPermi() 检查:
- 从Token中获取用户权限列表
- 判断是否包含 "project:manage:add"
↓
7. 结果:
- ✅ 有权限 → 执行Controller方法
- ❌ 无权限 → 返回403 Forbidden
1.4. 权限字符串的命名规范
权限字符串采用三段式命名:模块:功能:操作
例如:
project:manage:add- 项目管理模块-管理功能-新增操作project:manage:edit- 项目管理模块-管理功能-编辑操作project:manage:delete- 项目管理模块-管理功能-删除操作system:user:list- 系统管理模块-用户功能-列表查询
这些权限存储在数据库的 sys_menu 表中,perms 字段:
1.5. 完整的权限控制流程图
数据库设计:
┌─────────────────────────────────────┐
│ sys_menu (菜单权限表) │
├──────────┬──────────┬───────────────┤
│ menu_id │ perms │ menu_type │
├──────────┼──────────┼───────────────┤
│ 1 │ │ M (目录) │
│ 2 │ │ C (菜单) │
│ 3 │ project: │ F (按钮) │
│ │ manage: │ │
│ │ add │ │
└──────────┴──────────┴───────────────┘
↓
用户-角色-菜单关联:
┌──────────┐ ┌──────────┐ ┌──────────┐
│ sys_user │───→│sys_user_ │───→│ sys_role │
│ (用户表) │ │ role │ │ (角色表) │
└──────────┘ └──────────┘ └──────────┘
│
↓
┌──────────┐
│sys_role_ │
│ menu │
└──────────┘
│
↓
┌──────────┐
│ sys_menu │
│ (菜单表) │
└──────────┘
↓
用户登录时加载权限:
LoginUser {
userId: 1,
username: "admin",
permissions: [
"project:manage:add",
"project:manage:edit",
"system:user:list"
]
}
↓
Token中存储权限信息(JWT)
↓
请求拦截检查:
@PreAuthorize("@ss.hasPermi('project:manage:add')")
↓
PermissionService.hasPermi() 检查:
- 从SecurityContext获取当前用户
- 获取用户的permissions集合
- 判断是否包含所需权限
↓
结果:
✅ 有权限 → 执行方法
❌ 无权限 → 抛出异常,返回403
1.6. 特殊权限标识
在 PermissionService.java 中有一个特殊权限:
private static final String ALL_PERMISSION = "*:*:*";
超级管理员权限:如果用户的权限列表中包含 "*:*:*",则该用户拥有所有权限,可以访问任何接口。
更多推荐


所有评论(0)