🔐 一文掌握权限认证全家桶:角色控制、注解鉴权、会话二级认证、路由权限|Java 后端实战
✅ 写了 8 年 Java,权限系统是我重写最多的模块之一。
🚀 本文帮你构建一套灵活可扩展的权限认证框架,支持:
- 权限认证 / 角色认证
- 方法注解鉴权
- 路由级鉴权
- 会话二级认证(类似支付密码)
- 动态策略扩展
🧠 本质理解:权限系统 = 身份识别 + 能力匹配
权限认证的核心逻辑:
用户是谁(身份) → 拥有哪些角色 / 权限(能力) → 能不能访问某个资源 / 接口(动作)
🧱 权限模型设计(推荐 RBAC)
RBAC(基于角色的访问控制)结构如下:
- 用户(User)
- 角色(Role)
- 权限(Permission)
- 资源(Resource)
数据库表结构示意:
user → role → permission → resource
用户 → 角色 → 拥有哪些权限 → 对哪些资源生效
✨ 注解鉴权:最优雅的权限控制方式
我们先从最常见也是最推荐的做法开始 —— 自定义注解 + AOP 拦截 + 权限校验
📌 Step 1:定义权限注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiresPermission {
String value(); // 权限标识符
}
📌 Step 2:AOP 拦截鉴权逻辑
@Aspect
@Component
public class AuthAspect {
@Autowired
private PermissionService permissionService;
@Before("@annotation(requiresPermission)")
public void checkPermission(JoinPoint point, RequiresPermission requiresPermission) {
String permissionCode = requiresPermission.value();
String userId = AuthContext.getCurrentUserId(); // 获取当前登录用户
if (!permissionService.hasPermission(userId, permissionCode)) {
throw new NoPermissionException("无权限访问该接口");
}
}
}
📌 Step 3:使用示例
@GetMapping("/admin/user/list")
@RequiresPermission("user:view")
public List<User> listUsers() {
return userService.findAll();
}
🧩 角色认证:只需换注解
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiresRole {
String[] value();
boolean logicalAnd() default true; // 多个角色是 AND 还是 OR
}
AOP 拦截逻辑基本一致,判断用户是否包含指定角色。
🔁 会话二级认证:类似“支付密码”机制
某些接口(如提现、转账)需要用户 再次验证身份(密码、验证码等),这是会话级别的二次认证。
✅ 实现思路:
- 登录成功后生成一个
accessToken - 用户通过二级认证后,给当前会话打上“认证通过”的标记(存在 Redis)
@PostMapping("/auth/verify-password")
public ResponseEntity<?> verifyPassword(@RequestBody VerifyRequest req) {
String userId = AuthContext.getCurrentUserId();
if (userService.verifyPassword(userId, req.getPassword())) {
// 设置二级认证标记:有效期15分钟
redisTemplate.opsForValue().set("AUTH:SECOND:" + userId, "1", Duration.ofMinutes(15));
return ResponseEntity.ok("验证通过");
}
return ResponseEntity.status(401).body("验证失败");
}
在关键接口中校验:
@RequiresPermission("money:transfer")
@RequiresSecondAuth
@PostMapping("/money/transfer")
public ResponseEntity<?> transfer(...) {
...
}
AOP 拦截 @RequiresSecondAuth 注解,判断 Redis 是否存在认证标记。
📡 路由鉴权:前后端协同控制
有些系统需要前端根据权限动态渲染菜单或按钮,这就需要接口返回权限数据。
@GetMapping("/auth/user-info")
public UserInfo getUserInfo() {
User user = authService.getCurrentUser();
List<String> roles = roleService.getUserRoles(user.getId());
List<String> permissions = permissionService.getUserPermissions(user.getId());
return new UserInfo(user, roles, permissions);
}
前端拿到 permissions 后,动态控制路由和按钮显示。
🧩 权限校验核心服务代码
@Service
public class PermissionService {
@Autowired
private UserPermissionMapper userPermissionMapper;
public boolean hasPermission(String userId, String permissionCode) {
List<String> permissions = userPermissionMapper.getPermissionsByUserId(userId);
return permissions.contains(permissionCode);
}
}
🔄 支持动态权限策略(可插拔)
你可以将权限策略抽象成接口,实现多种校验方式:
public interface PermissionStrategy {
boolean isAllowed(String userId, String permissionCode);
}
然后通过配置选择使用哪种策略:
@Configuration
public class AuthConfig {
@Value("${auth.strategy}")
private String strategy;
@Bean
public PermissionStrategy permissionStrategy() {
if ("RBAC".equals(strategy)) {
return new RbacPermissionStrategy();
} else if ("ABAC".equals(strategy)) {
return new AbacPermissionStrategy(); // 支持条件属性判断
}
return new DefaultStrategy();
}
}
✅ 总结
| 功能点 | 实现方式 |
|---|---|
| 权限认证 | 自定义注解 + AOP 拦截 |
| 角色认证 | 自定义注解 + 多角色支持 |
| 二级认证 | Redis 标记 + 注解拦截 |
| 路由级权限控制 | 后端返回权限列表,前端动态路由 |
| 策略可插拔 | 接口 + 策略模式 |
📌 最后
权限系统本质上是一个 “安全 + 灵活 + 可扩展” 的模块,关键是:
- 拦截时机(注解 + AOP)
- 权限数据结构清晰
- 策略设计可扩展
- 前后端协同做好体验
这套方案已在多个项目中跑通,支持数十万人使用,稳定、安全、灵活。
作者:一个写了 8 年 Java 的后端老兵,热衷于用优雅的代码解决复杂问题。