背景
是 Spring Security 框架中的一个注解,用于在方法级别进行权限控制。它的作用是 在执行被注解的方法之前,检查当前用户是否拥有指定的权限,如果没有权限则抛出
@PreAuthorize("@pms.hasPermission('user_add')")。
AccessDeniedException
代码解析
1.
@PreAuthorize 注解
@PreAuthorize
作用:Spring Security 提供的 方法级安全注解,用于在方法调用前进行权限校验。类似注解:
:方法执行后校验权限(较少用)。
@PostAuthorize:更简单的权限控制(但不如
@Secured 灵活)。
@PreAuthorize
2.
@pms.hasPermission('user_add')
@pms.hasPermission('user_add')
:这是一个 SpEL(Spring Expression Language)表达式,引用了一个名为
@pms 的 Spring Bean。
pms:调用
hasPermission('user_add') Bean 的
pms 方法,检查当前用户是否拥有
hasPermission 权限。
'user_add'
底层原理
Spring Security 执行流程:
当调用被 注解的方法时,Spring Security 会先解析 SpEL 表达式。它会查找
@PreAuthorize Bean(通常是一个自定义的权限管理服务)。调用
pms,返回
pms.hasPermission('user_add')(允许访问)或
true(拒绝访问)。
false
Bean 的典型实现:
pms
通常是一个自定义的权限服务,例如:
@Service("pms")
public class PermissionService {
public boolean hasPermission(String permission) {
// 1. 获取当前用户(从 SecurityContext)
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
// 2. 检查用户是否拥有该权限(可能查数据库、Redis 或内存缓存)
return auth.getAuthorities().stream()
.anyMatch(auth -> auth.getAuthority().equals(permission));
}
}
也可以集成 RBAC(基于角色的权限控制),例如:
public boolean hasPermission(String permission) {
UserDetails user = (UserDetails) SecurityContextHolder.getContext().getAuthentication().getPrincipal();
return user.getAuthorities().stream()
.anyMatch(auth -> auth.getAuthority().equals("ROLE_ADMIN") || auth.getAuthority().equals(permission));
}
使用场景
适用场景:
限制某些方法只能由特定权限的用户调用(如 、
user_add)。动态权限控制(如基于数据库的权限管理)。
user_delete
示例:
@RestController
@RequestMapping("/users")
public class userController {
@PostMapping
@PreAuthorize("@pms.hasPermission('user_add')")
public ResponseEntity<String> adduser() {
return ResponseEntity.ok("user added successfully!");
}
@DeleteMapping("/{id}")
@PreAuthorize("@pms.hasPermission('user_delete')")
public ResponseEntity<String> deleteuser(@PathVariable Long id) {
return ResponseEntity.ok("user deleted successfully!");
}
}
只有拥有 权限的用户才能调用
user_add。只有拥有
adduser() 权限的用户才能调用
user_delete。
deleteuser()
常见问题
Bean 未找到:
pms
确保 被 Spring 管理(加了
PermissionService 或
@Service)。确保 Bean 的名称是
@Component(
pms)。
@Service("pms")
权限校验失败:
检查当前用户是否登录()。检查用户的权限是否包含
SecurityContextHolder.getContext().getAuthentication()。
user_add
SpEL 表达式错误:
确保表达式语法正确,例如 而不是
@pms.hasPermission('user_add')(缺少引号)。
@pms.hasPermission(user_add)
总结
| 组件 | 说明 |
|---|---|
|
Spring Security 方法级权限控制注解 |
|
引用名为 的 Spring Bean |
|
调用 Bean 的方法,检查当前用户是否有 权限 |
作用:确保只有拥有 权限的用户才能执行该方法,否则拒绝访问。
user_add
适用场景:动态权限控制、RBAC(基于角色的访问控制)。
