mldong 快速开发框架权限系统设计与实现

一、权限系统的核心目标

  • 用户身份识别:支持用户名/密码登录、第三方授权登录。
  • 接口访问控制:通过注解方式实现接口级别的权限控制。
  • 动态权限分配:支持角色绑定菜单权限、用户绑定角色关系。
  • 在线用户管理:查看当前在线用户、强制登出或踢下线操作。
  • 多租户与字段级权限(可扩展):为后续功能预留空间。

二、RBAC 权限模型详解

核心概念

实体 描述
User 用户实体,存储用户基本信息
Role 角色实体,定义角色名称、编码等
Menu 菜单实体,包含菜单名、编码、应用标识
UserRole 用户与角色的关系表
RoleMenu 角色与菜单的关联表

数据库结构图解(ER 图)


三、Sa-Token 登录认证流程解析

登录接口 /sys/login

java 复制代码
@PostMapping("/sys/login")
@ApiOperation(value="登录")
public CommonResult<?> login(@RequestBody @Validated LoginParam param) {
    if(ConstantContextHolder.getCaptchaOpenFlag()){
        if(!captchaManager.validate(HttpServletUtil.getRequest())) {
            return CommonResult.fail(SysErrEnum.CAPTCHA_ERROR);
        }
    }
    return CommonResult.data(authService.login(param));
}

登录逻辑核心步骤:

  1. 验证码验证:根据配置决定是否启用验证码;
  2. 用户名/手机号 + 密码验证 :
    • 查询用户是否存在;
    • 验证密码是否正确;
  3. 自定义登录处理器:用于处理第三方登录逻辑(如 OAuth2、短信登录等);
  4. 生成 Token 并绑定用户信息:使用 Sa-Token 进行登录,并将用户信息注入 Token 中;
  5. 记录登录日志:成功/失败日志记录,便于后续审计。

四、接口权限控制实现

使用 @SaCheckPermission 注解

在控制器方法上添加注解即可实现权限控制:

java 复制代码
@PostMapping("/sys/role/save")
@ApiOperation(value = "添加角色")
@SaCheckPermission("sys:role:save")
public CommonResult<?> save(@RequestBody @Validated({Groups.Save.class}) RoleParam param) {
    roleService.save(param);
    return CommonResult.ok();
}

支持 OR/AND 权限组合

java 复制代码
@PostMapping("/sys/rbac/roleMenuIds")
@SaCheckPermission(value = {"sys:rbac:roleMenuIds","sys:rbac:saveRoleMenu"}, mode = SaMode.OR)
public CommonResult<List<Long>> roleMenuIds(@RequestBody RoleMenuParam param){
    return  CommonResult.data(rbacService.roleMenuIds(param.getRoleId()));
}

权限验证原理(AuthService)

java 复制代码
@Override
public List<String> getPermissionList(Object loginId, String loginType) {
    LoginUser loginUser = LoginUserHolder.me();
    List<String> perms = new ArrayList<>();
    if (AdminTypeEnum.SUPER_ADMIN.getCode().equals(loginUser.getAdminType())) {
        perms.add(CommonConstant.SUPER_ADMIN_PERM_FLAG);
    } else {
        RbacService rbacService = SpringUtil.getBean(RbacService.class);
        perms.addAll(rbacService.getPermInCache(loginUser.getRoleIds(), loginUser.getAppCode()));
    }
    return perms;
}

五、角色权限分配机制

分配角色菜单权限 /sys/rbac/saveRoleMenu

java 复制代码
@PostMapping("/sys/rbac/saveRoleMenu")
@ApiOperation(value="添加角色菜单")
@SaCheckPermission("sys:rbac:saveRoleMenu")
public CommonResult<?> saveRoleMenu(@RequestBody List<RoleMenuParam> param) {
    boolean isSuccess = rbacService.saveRoleMenu(param);
    if(isSuccess) {
        return CommonResult.ok("添加角色菜单成功");
    } else {
        return CommonResult.fail("添加角色菜单失败");
    }
}

核心逻辑:

  • 删除旧缓存;
  • 清除已有菜单权限;
  • 重新插入新的角色菜单关系;
  • 异步刷新缓存(避免影响主线程性能);

获取角色菜单列表 /sys/rbac/roleMenuList

java 复制代码
@PostMapping("/sys/rbac/roleMenuList")
@ApiOperation(value="获取角色菜单列表")
@SaCheckPermission("sys:rbac:roleMenuList")
public CommonResult<List<MenuVO>> roleMenuList(@RequestBody @Validated RoleMenuPageParam param) {
    return CommonResult.data(rbacService.roleMenuList(param));
}

六、用户角色管理 /sys/user/grantRole

java 复制代码
@PostMapping("/sys/user/grantRole")
@ApiOperation(value = "授权角色")
@SaCheckPermission("sys:user:grantRole")
public CommonResult<?> grantRole(@RequestBody @Validated({UserRoleParam.GrantRole.class}) UserRoleParam param) {
    userService.grantRole(param.getUserId(), param.getRoleIdList());
    return CommonResult.ok();
}

动态刷新权限机制

  • 修改角色后会清空用户的 Token 缓存;
  • 下次请求时自动加载新权限;
  • 若需立即生效,可调用 StpUtil.logout(userId) 强制登出。

七、在线用户管理 /sys/user/onlineUserList

java 复制代码
@PostMapping("/sys/user/onlineUserList")
@ApiOperation(value = "获取在线用户列表")
@SaCheckPermission("sys:user:onlineUserList")
public CommonResult<List<LoginUser>> onlineUserList(@RequestBody @Validated UserPageParam param) {
    return CommonResult.data(userService.onlineUserList(param));
}

查看当前在线设备

java 复制代码
@PostMapping("/sys/user/onlineDevice")
@ApiOperation(value = "个人-获取在线设备")
public CommonResult<List<LoginUser>> onlineDevice() {
    return CommonResult.data(userService.onlineDevice(LoginUserHolder.getUserId()));
}

支持 Token 级别操作

  • 强制注销 :logoutByTokenValue
  • 踢下线 :kickoutByTokenValue

八、关键类职责划分一览表

类名 职责说明
AuthController 登录、退出、验证码、扮演用户、第三方账号绑定
UserService 用户 CRUD、角色绑定、修改密码、在线状态维护
RoleService 角色创建、更新、查询
MenuService 菜单资源创建、更新、查询
RbacService 角色权限分配、菜单权限查询、用户角色管理
AuthService 登录逻辑、权限计算、扮演用户逻辑
AuthInterceptor 自定义拦截器,用于演示环境限制访问

九、总结与建议

✅ 已有优势:

  • 基于 Sa-Token 实现,轻量且高性能;
  • 支持动态权限分配,实时生效;
  • 接口权限控制粒度细,支持 OR/AND 组合;
  • 提供完整的在线用户管理功能;
  • 支持第三方账号绑定,灵活扩展。

💡 可优化方向:

  • 权限变更日志记录:记录谁在何时修改了什么权限;
  • 字段级权限控制:未来可扩展支持数据字段级权限;
  • 多租户支持:为 SaaS 架构做准备;
  • 权限继承机制:角色之间支持继承关系,简化配置。

十、结语

欢迎关注【mldong】开源项目,后续将持续分享权限扩展、低代码平台构建等内容。

如果你也想打造一个灵活可扩展的权限系统,欢迎 Star 我们的开源项目 mldong。

更多关于权限、低代码平台构建的内容,欢迎关注【mldong】公众号,第一时间获取更新通知!


📌 如需获取完整源码,请访问 Gitee 地址:

🔗 gitee.com/mldong/mldo...


💬 "你在权限系统中遇到过哪些坑?欢迎留言交流。"

相关推荐
程序猿DD1 小时前
OctaFuse Gateway 2.15.0:MCP 聚合、向量 Embeddings 与官方目录同步
后端·agent
安易算力3 小时前
昇腾CANN算子开发与MindSpore部署调优实践:从Ascend C到模型推理全链路
网络·架构
蛋蛋的就会顺顺的3 小时前
hot100 p0——栈,贪心算法,动态规划
java·前端·javascript·算法·leetcode·力扣
余槐i3 小时前
PostgreSQL 函数索引报错 must be immutable:3种绕法与代价
数据库·后端·sql·postgresql·性能优化
需要8264 小时前
Spring Bean 生命周期:从实例化到销毁的完整钩子
java·后端·spring
小 黄 鸡4 小时前
HashMap 面试必会知识点详解(JDK 8)
java·面试·职场和发展
凤山老林5 小时前
Spring Boot 接入国密 SM2/SM3/SM4 的一些实践记录
spring boot·后端·python
伯恩bourne6 小时前
Spring Boot Bean 注册的两种方式:@Component 家族 vs @Configuration + @Bean
java·spring boot·后端
张彦峰ZYF6 小时前
停顿短不等于延迟低:G1、ZGC 与低延迟服务的目标分野、代价账本与选型标定
后端·回收暂停、应用停止总时长·到达安全点、分配停滞·屏障吃吞吐、并发线程吃核心·并发窗口吃堆余量·分区式靠挑回收集兑现目标·染色指针式不支持压缩引用
silvamux_6 小时前
curl 测试 OpenAI 兼容 API 的完整流程
java·人工智能·缓存·ai·oneapi