🔐 一文掌握权限认证全家桶:角色控制、注解鉴权、会话二级认证、路由权限|Java 后端实战

69 阅读3分钟

🔐 一文掌握权限认证全家桶:角色控制、注解鉴权、会话二级认证、路由权限|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 的后端老兵,热衷于用优雅的代码解决复杂问题。