功能权限与数据权限
接口先问「能不能进」,再问「能看见哪些行」。功能权限卡菜单和按钮;数据权限在 Mapper 执行前拼 WHERE。字段级脱敏不在本篇。默认端口 48080,前缀 /admin-api。
示意图:用户挂角色,角色勾菜单。菜单上的 permission 就是接口权限字。
怎么配
采用 RBAC。菜单里既有侧栏目录,也有按钮。超管角色走 PermissionServiceImpl 特判,不必逐条对齐。
- 系统管理 → 菜单管理:维护路由、组件、
permission、可见端、mobile_path、关联流程。 - 系统管理 → 角色管理:行内「菜单权限」勾树;「数据权限」选行范围。
- 用户挂角色后重新登录(或等权限缓存失效)再生效。

本系统截图:系统管理 → 菜单管理。permission 列给后端 @PreAuthorize 和前端 auth 用。

本系统截图:系统管理 → 角色管理。行内「菜单权限」「数据权限」。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
RoleDO | code 给 @ss.hasRole,dataScope 给行范围 | ruoyi-office/yudao-module-system/.../dal/dataobject/permission/RoleDO.java |
MenuDO | permission 形如 system:user:create | 同目录 MenuDO.java |
UserRoleDO | 表 system_user_role,@TenantIgnore | UserRoleDO.java |
RoleMenuDO | 表 system_role_menu | RoleMenuDO.java |
| 角色页 | 分配菜单、数据范围 | ruoyi-office-vben/apps/web-antd/src/views/system/role/ |
| 菜单页 | 路由与权限标识 | src/views/system/menu/ |
菜单 id:官方 1–9999,客户二开 10000–99999。见 MenuDO.OFFICIAL_ID_MAX。
用户角色关联不要带租户过滤
UserRoleDO 标了 @TenantIgnore。否则访问其它租户时,超管角色会被查成空集并写入 Redis,随后全站报「没有该操作权限」。
流程发起也走菜单
授权唯一源是 system_menu + system_role_menu。大厅和 App 能不能发起某张单,用流程定义 Key 反查 system_menu.process_definition_key,再取该菜单的 permission 判权。
canStart(user) =
hasAnyPermission(menuPermissionsOf(processKey))
AND orgScopePass(startUserIds / startDeptIds)
AND visible AND !suspendedstartUserIds / startDeptIds 只收窄,不做授权。端可见性看菜单 client_type + mobile_path,PC 树、App 工作台、发起列表同源。process_definition_key 支持逗号分隔别名。
| 配置 | 位置 |
|---|---|
| 能力授权 | 角色 → 菜单权限 |
| 关联流程 / 可见端 | 菜单:关联流程、client_type、mobile_path |
| 配置自检 | 系统管理 → 配置体检 |
| 发起范围 | 流程模型 → 谁可以发起 |
流程表单(formType = 10)没有业务 list/info 时,在模型第二步填 menuConfig,发布时自动 upsert 列表菜单 + 创建按钮。权限码形如 bpm:process-form:{key}:create。不会自动给角色勾上,还要去角色树勾一次。业务表单继续走代码生成的 list/info,创建按钮绑 Key。
未绑菜单的存量流程默认仍可发,会在配置体检标出。yudao.bpm.start-permission.required=true 才会禁止未纳入管控的流程。系统代发起(定时任务、代他人发起)跳过发起权限。
详见 流程配置。
功能权限
Token 认证
登录不走 Spring Security 表单。验证码、刷新令牌在 AuthController。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
| 登录 | @RequestMapping("/system/auth"),POST /login,@PermitAll | yudao-module-system/.../controller/admin/auth/AuthController.java |
| 请求头 | Authorization: Bearer {accessToken} | ruoyi-office-vben/apps/web-antd/src/api/request.ts |
| 过滤器 | 校验 Token,写入 LoginUser | yudao-framework/yudao-spring-boot-starter-security/.../filter/TokenAuthenticationFilter.java |
| 落库 | system_oauth2_access_token | OAuth2AccessTokenDO |
过期时间看 system_oauth2_client 里 client_id = default。登出、改密码会删库并删 Redis。本地联调可开 yudao.security.mock-enable: true,Authorization: Bearer test1 表示用户 1。生产必须关掉。
权限注解
@ss 是 SecurityFrameworkServiceImpl 的 Bean 名,落到 PermissionServiceImpl。EL 为 false 时返回 403。
@PostMapping("/create")
@PreAuthorize("@ss.hasPermission('system:user:create')")
public CommonResult<Long> createUser(@Valid @RequestBody UserSaveReqVO reqVO) {
return success(userService.createUser(reqVO));
}也可用 @ss.hasAnyPermissions、@ss.hasRole、@ss.hasAnyRoles。标识与 system_menu.permission 对齐,推荐 ${系统}:${模块}:${操作}。前端按钮用同一套码:TableAction 的 auth、v-access:code。
查询接口尽量放权(仍须登录):列表 /page /get 不要另挂 :query;选择器走 select-page。禁止在原先没有 @PreAuthorize 的接口上新增权限。增删改导出才勾按钮。
hasAnyPermissions 的本地缓存 key 是 userId + 会话部门,且只缓存 true。多组织切换任职后,不会用旧部门的权限码卡住。
匿名访问
默认 /admin-api/**、/app-api/** 都要登录。免登录三种方式:模块 AuthorizeRequestsCustomizer、方法 @PermitAll、配置 yudao.security.permit-all-urls。permitAll() 带不带 Token 都能进;anonymous() 带着 Token 反而失败。
数据权限
同一张表,不同角色看到的行不同。组件是 yudao-spring-boot-starter-biz-data-permission。这是行权限,不能靠它隐藏某一列。
角色上的 dataScope 对应五种范围,在角色列表点「数据权限」配置。
| 名称 | 说明 | 仓库路径 |
|---|---|---|
ALL | 1 全部,不拼条件 | yudao-module-system-api/.../enums/permission/DataScopeEnum.java |
DEPT_CUSTOM | 2 指定部门,用 dataScopeDeptIds | 同上 |
DEPT_ONLY | 3 本部门 | 同上 |
DEPT_AND_CHILD | 4 本部门及下级 | 同上 |
SELF | 5 仅本人 | 同上 |

本系统截图:为角色选择权限范围。选「指定部门」时再勾部门树。
DataPermissionRuleHandler 在 SELECT / UPDATE / DELETE 上追加条件。system 模块用 DeptDataPermissionRuleCustomizer 声明:AdminUserDO 按 dept_id,部门表按 id,本人按用户 id。
手写 XML 不会自动拼条件
列表、更新、删除请走 Mapper 方法或 Wrapper。
数据权限默认开启。个人中心、getPermissionInfo 要关,否则「仅本人」会把自己的部门滤掉:@DataPermission(enable = false) 或 DataPermissionUtils.executeIgnore。Feign 只传 data-permission-enable,includeRules 跨服务传不过去。
自定义规则实现 DataPermissionRule,声明成 Bean:getTableNames() + getExpression()。
配置与操作
功能权限写在菜单 permission,接口 @PreAuthorize("@ss.hasPermission")。数据权限在角色「设置数据权限」(菜单 id 1064),改 data_scope 后新查询生效。开启见 框架层。
