一、权限系统的核心目标
- 用户身份识别:支持用户名/密码登录、第三方授权登录。
- 接口访问控制:通过注解方式实现接口级别的权限控制。
- 动态权限分配:支持角色绑定菜单权限、用户绑定角色关系。
- 在线用户管理:查看当前在线用户、强制登出或踢下线操作。
- 多租户与字段级权限(可扩展):为后续功能预留空间。
二、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));
}
登录逻辑核心步骤:
- 验证码验证:根据配置决定是否启用验证码;
- 用户名/手机号 + 密码验证 :
- 查询用户是否存在;
- 验证密码是否正确;
- 自定义登录处理器:用于处理第三方登录逻辑(如 OAuth2、短信登录等);
- 生成 Token 并绑定用户信息:使用 Sa-Token 进行登录,并将用户信息注入 Token 中;
- 记录登录日志:成功/失败日志记录,便于后续审计。
四、接口权限控制实现
使用 @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 地址:
💬 "你在权限系统中遇到过哪些坑?欢迎留言交流。"