feat(role): role bind
This commit is contained in:
@@ -149,6 +149,17 @@
|
||||
|
||||
下一步依赖:`access_token`。
|
||||
|
||||
(可选)使用 refresh_token 自动续期:
|
||||
|
||||
- **POST** `/auth/refresh`
|
||||
- Tag:`Auth`
|
||||
- Header:无
|
||||
- Body:
|
||||
|
||||
```json
|
||||
{ "refresh_token": "<opaque>" }
|
||||
```
|
||||
|
||||
### Step 3:获取当前租户信息(Tenant)
|
||||
|
||||
**GET** `/tenants/me`
|
||||
@@ -319,6 +330,133 @@ enabled_apps 维护建议:
|
||||
{ "code": 0, "message": "Success", "data": [{ "id": "<role_id>", "name": "Admin", "description": "..." }], "trace_id": null }
|
||||
```
|
||||
|
||||
## Role & Permission Management
|
||||
|
||||
本节补齐“角色(Role)与权限(Permission)管理”的完整指引,适用于横向扩展到多个应用(如 `cms` / `tms` / `iam` 等)。
|
||||
|
||||
### 权限模型(可扩展到十几个应用)
|
||||
|
||||
权限编码规范:
|
||||
- `permission.code` 统一采用:`${app_code}:${resource}:${action}`
|
||||
- 示例:`cms:article:publish`、`tms:task:assign`、`iam:tenant:enabled_apps:write`
|
||||
- `app_code` 必须与应用注册表(app_registry)中的应用标识一致(本项目对应表为 `apps.id`)。
|
||||
- 支持通配符(需要在 `permissions.code` 中显式存储通配符权限并分配到角色):
|
||||
- `cms:*:*`:CMS 全权限
|
||||
- `cms:article:*`:文章相关全权限
|
||||
|
||||
> 说明:鉴权时支持通配符匹配(例如持有 `cms:article:*` 可满足 `cms:article:publish`),但只有当该通配符权限被写入 `permissions` 并绑定到角色时才会生效。
|
||||
|
||||
数据库关系(ER 图):
|
||||
|
||||
```mermaid
|
||||
erDiagram
|
||||
apps {
|
||||
VARCHAR id PK
|
||||
VARCHAR name
|
||||
VARCHAR status
|
||||
}
|
||||
permissions {
|
||||
UUID id PK
|
||||
VARCHAR code
|
||||
TEXT description
|
||||
VARCHAR resource
|
||||
VARCHAR action
|
||||
}
|
||||
users {
|
||||
UUID id PK
|
||||
UUID tenant_id FK
|
||||
VARCHAR email
|
||||
}
|
||||
roles {
|
||||
UUID id PK
|
||||
UUID tenant_id FK
|
||||
VARCHAR name
|
||||
BOOLEAN is_system
|
||||
}
|
||||
role_permissions {
|
||||
UUID role_id FK
|
||||
UUID permission_id FK
|
||||
}
|
||||
user_roles {
|
||||
UUID user_id FK
|
||||
UUID role_id FK
|
||||
}
|
||||
|
||||
apps ||--o{ permissions : namespaces
|
||||
roles ||--o{ role_permissions : grants
|
||||
permissions ||--o{ role_permissions : assigned
|
||||
users ||--o{ user_roles : has
|
||||
roles ||--o{ user_roles : assigned
|
||||
```
|
||||
|
||||
应用区分方式:
|
||||
- 通过 `apps`(app_registry)维护“允许的应用标识”,并要求权限码的 `app_code` 与 `apps.id` 一致。
|
||||
- 在租户侧通过 `enabled_apps` 控制某租户开通哪些应用;登录/权限查询会按 `enabled_apps` 过滤应用级权限(例如 `cms:*:*` 会在租户未开通 `cms` 时被过滤)。
|
||||
|
||||
### 1) 为 CMS 添加最小必要权限(SQL)
|
||||
|
||||
脚本位置:`scripts/db/migrations/0006_cms_permissions.sql`
|
||||
|
||||
包含权限项:
|
||||
- 文章:创建、编辑、发布
|
||||
- 栏目:管理
|
||||
- 媒体库:管理
|
||||
- 系统配置:管理
|
||||
|
||||
### 2) 查询权限列表(分页/搜索)
|
||||
|
||||
**GET** `/permissions?page=1&page_size=20&app_code=cms&search=article`
|
||||
|
||||
- Tag:`Permission`
|
||||
- Header:`Authorization: Bearer <access_token>`
|
||||
- 需要权限:`role:read`
|
||||
|
||||
### 3) 角色 CRUD(Role)
|
||||
|
||||
创建角色:
|
||||
- **POST** `/roles`
|
||||
|
||||
查询角色详情:
|
||||
- **GET** `/roles/{id}`
|
||||
|
||||
更新角色:
|
||||
- **PATCH** `/roles/{id}`
|
||||
|
||||
删除角色:
|
||||
- **DELETE** `/roles/{id}`
|
||||
|
||||
说明:
|
||||
- 系统内置角色(`is_system=true`,如 `Admin`)不允许通过 API 修改/删除。
|
||||
|
||||
### 4) 为角色批量绑定/解绑权限
|
||||
|
||||
绑定权限(批量):
|
||||
- **POST** `/roles/{id}/permissions/grant`
|
||||
- Body:
|
||||
|
||||
```json
|
||||
{ "permission_codes": ["cms:article:create", "cms:article:publish"] }
|
||||
```
|
||||
|
||||
解绑权限(批量):
|
||||
- **POST** `/roles/{id}/permissions/revoke`
|
||||
|
||||
### 5) 批量给用户授予/回收角色
|
||||
|
||||
批量授予:
|
||||
- **POST** `/roles/{id}/users/grant`
|
||||
- Body:
|
||||
|
||||
```json
|
||||
{ "user_ids": ["<user_id_1>", "<user_id_2>"] }
|
||||
```
|
||||
|
||||
批量回收:
|
||||
- **POST** `/roles/{id}/users/revoke`
|
||||
|
||||
审计说明:
|
||||
- 角色创建/更新/删除、角色-权限绑定/解绑、角色-用户授予/回收都会写入 `audit_logs`。
|
||||
|
||||
### Step 7:用户-角色绑定(User)
|
||||
|
||||
用户注册后默认无角色;通常由具备 `user:write` 的管理员进行角色分配。
|
||||
|
||||
40
docs/TEMP.md
40
docs/TEMP.md
@@ -1,23 +1,55 @@
|
||||
`00000000-0000-0000-0000-000000000001`
|
||||
`superadmin@example.com`
|
||||
`superadmin1234`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "Success",
|
||||
"data": {
|
||||
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI3YTgzYmJjMC0yZjA1LTQwMDItOGFmZC0yYWI1M2RkZDMxNWIiLCJ0ZW5hbnRfaWQiOiI0ZDc3OTQxNC1kYTA0LTQ5YzMtYjM0Mi1kYWJmOTNiNmExMTkiLCJleHAiOjE3Njk3NTc3MTAsImlhdCI6MTc2OTc1NjgxMCwiaXNzIjoiaWFtLXNlcnZpY2UiLCJyb2xlcyI6WyJBZG1pbiJdLCJwZXJtaXNzaW9ucyI6WyJyb2xlOnJlYWQiLCJyb2xlOndyaXRlIiwidGVuYW50OnJlYWQiLCJ0ZW5hbnQ6d3JpdGUiLCJ1c2VyOnJlYWQiLCJ1c2VyOndyaXRlIl19.VGsoZdMwodRWKW4NQuQwezh3xZivFbRUzSw_-RnD-EJIv7qPHmcNbdIcxNSKXCHGKdK_b1B3404m7ji2wdEOweKz0GEcwPWswc9fannP5_6l9k83jn0ZKQ1pS3l27V5mr9feym_83ZIqEtFfKcCKGIM684Ze7CMM6i-gfYisn0poG1XW3K4ptsVnuNZux0TWNFl5TO6kgiw0_399tZnSH5qc4CckHOuoF3Jz1Q2aIgnvyfxbxEFTNZm-ykjhlbK5zWBpYfJdYOALQg-FQ3eGuVnSF4U_If1MNQKQ0p6DqDKMCO0IfdCr2WMBvfCYA1SxmPbETr2Tm7RguhJBEiVQ4Q",
|
||||
"refresh_token": "e1649e730ef3583cd80087f7fa63774330deb88e81aec2edae41322764e441eb",
|
||||
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI4YWRlYzEzOC0wMzU5LTQ5NjgtYjAzNy03ZDI3Nzg2NTZhNjIiLCJ0ZW5hbnRfaWQiOiIwMDAwMDAwMC0wMDAwLTAwMDAtMDAwMC0wMDAwMDAwMDAwMDEiLCJleHAiOjE3Njk4NTA1ODIsImlhdCI6MTc2OTg0OTY4MiwiaXNzIjoiaWFtLXNlcnZpY2UiLCJyb2xlcyI6WyJBZG1pbiJdLCJwZXJtaXNzaW9ucyI6WyJpYW06dGVuYW50OmVuYWJsZWRfYXBwczpyZWFkIiwiaWFtOnRlbmFudDplbmFibGVkX2FwcHM6d3JpdGUiLCJyb2xlOnJlYWQiLCJyb2xlOndyaXRlIiwidGVuYW50OnJlYWQiLCJ0ZW5hbnQ6d3JpdGUiLCJ1c2VyOnBhc3N3b3JkOnJlc2V0OmFueSIsInVzZXI6cmVhZCIsInVzZXI6d3JpdGUiXSwiYXBwcyI6W10sImFwcHNfdmVyc2lvbiI6MH0.JouDbnuLxCIXl4CpZ3G3zcwILohS1Dv6_k-2pV_5Iezrnk9IGlnmv-TqhP1BB0_A88etOIV9EPx8LVD0dJQaci_jABVr9ciQU126yu8GeTkoJTKDXuroornAxv6C7K2qp7jl9lfxgmm0h0jYla79YdEW8RdDu8q9VojjVNnyiT-0thOKRJddflKjovOrlOsVpqjtZvf_F86e9vEFBFImUs8_xuWo3gUUysbINbZc-I-DGRqIC95pVOOts3LzashkIVlPl4akXpbukSJjwNd9WnTSr9zf-7bN_YBFJGSutLor74cMlklZ6k828GmHrsuAIxyZMqoeTLrrsG3VcUjYKQ",
|
||||
"refresh_token": "46d067317f9a6181255d151b099311b609683baa0c25ff62a81a3e6e7d8a9942",
|
||||
"token_type": "Bearer",
|
||||
"expires_in": 900
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
`4d779414-da04-49c3-b342-dabf93b6a119`
|
||||
`shay7sev@gmail.com`
|
||||
`tenantdev1`
|
||||
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "Success",
|
||||
"data": {
|
||||
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJmOTg5MWI2Yy0xNTQ1LTQ0NGItODIxOC0yNTQ5MDA1NDczMGYiLCJ0ZW5hbnRfaWQiOiI0ZDc3OTQxNC1kYTA0LTQ5YzMtYjM0Mi1kYWJmOTNiNmExMTkiLCJleHAiOjE3Njk3NTg4NDMsImlhdCI6MTc2OTc1Nzk0MywiaXNzIjoiaWFtLXNlcnZpY2UiLCJyb2xlcyI6W10sInBlcm1pc3Npb25zIjpbXX0.Is-JjQ9l1BuZoYVr6QAt-4ZSfRQro3COPSVYHVl1NI0CAz7T2x9Hz2QiJPFamjsX7cFrCIJxNMn9ioqK2FzEnSTu2oVATqlhE5OMCcK1M7Mq_FvZ7WqGgPl8CE06s7yvneC97mknk5y1-nm5claYYGeHAjLrRPbjO2t3zUQO5boNPdjzEGx4kTFvgmJbwWMrsBtkeaW1nacxhFiSj-RFCSzHOOaSRoKLDsx9nUsuDJL1NCaHDuKDacphkwpjP5AWLd41hlrs6PC8XLUPey2EXHqJ5SmOaDdQ60LfItvohgHBTY6CO8IUIJgtZobrFsKUlnHqA9eZwm2dvAW560g4VA",
|
||||
"refresh_token": "71e3ba6285b503891294ca7dad81cdc6bd5b3f72b09b1e2b796979a433d687f3",
|
||||
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiI3YTgzYmJjMC0yZjA1LTQwMDItOGFmZC0yYWI1M2RkZDMxNWIiLCJ0ZW5hbnRfaWQiOiI0ZDc3OTQxNC1kYTA0LTQ5YzMtYjM0Mi1kYWJmOTNiNmExMTkiLCJleHAiOjE3Njk4NTEyOTIsImlhdCI6MTc2OTg1MDM5MiwiaXNzIjoiaWFtLXNlcnZpY2UiLCJyb2xlcyI6WyJBZG1pbiJdLCJwZXJtaXNzaW9ucyI6WyJyb2xlOnJlYWQiLCJyb2xlOndyaXRlIiwidGVuYW50OnJlYWQiLCJ0ZW5hbnQ6d3JpdGUiLCJ1c2VyOnBhc3N3b3JkOnJlc2V0OmFueSIsInVzZXI6cmVhZCIsInVzZXI6d3JpdGUiXSwiYXBwcyI6WyJjbXMiXSwiYXBwc192ZXJzaW9uIjoxfQ.jt1os6re3yhxBk4wfmBjy1_Qh8n5nkfwe8ptn-yi7Vws_MOepOAmdxqSY_sabOnvGZ74Rq2EFSDpOaan4HuPln35Vlt6-CPlEu5eikLu3AIBl7sZfGoOquHwnybuOwo8b5oFwgAWF0bqSmn1v--LdGvv7vX4zWiKxK6GeeCTZ8279GqO70tl4o6ug2swSMqPbspL-ZwnWrnvFRhfZkyrRmM6jn3TVUMFWX3FfTlm68lNl_UPj9OcUPvbIXFL3X-h8qk-W1Dq2hV_Z1WxjkwVV0XEa0iwz12Mb_-QFys2xLSXSxL4ubUJhV2RVQ2WmW-I0njLEJAQ5oR56nZi7XMZHA",
|
||||
"refresh_token": "982236b2f680366a895768df1ffc29bf4bbc09eb82d6a88a4413a07f66b3badb",
|
||||
"token_type": "Bearer",
|
||||
"expires_in": 900
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`user1@example.com`
|
||||
`user1secret`
|
||||
|
||||
```json
|
||||
{
|
||||
"code": 0,
|
||||
"message": "Success",
|
||||
"data": {
|
||||
"access_token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJzdWIiOiJmOTg5MWI2Yy0xNTQ1LTQ0NGItODIxOC0yNTQ5MDA1NDczMGYiLCJ0ZW5hbnRfaWQiOiI0ZDc3OTQxNC1kYTA0LTQ5YzMtYjM0Mi1kYWJmOTNiNmExMTkiLCJleHAiOjE3Njk4NTE1NDYsImlhdCI6MTc2OTg1MDY0NiwiaXNzIjoiaWFtLXNlcnZpY2UiLCJyb2xlcyI6WyJlZGl0b3IiXSwicGVybWlzc2lvbnMiOlsiY21zOmFydGljbGU6Y3JlYXRlIiwiY21zOmFydGljbGU6ZWRpdCIsImNtczphcnRpY2xlOnB1Ymxpc2giXSwiYXBwcyI6WyJjbXMiXSwiYXBwc192ZXJzaW9uIjoxfQ.r3G5AVkJuvR9vqZhv2Gnj-kZT04Vp_FWNLaZxU7mCvq6uo0unv0d4n3kxDnVYnTYi8cAMtYd4OXvAcpyJ6cN1c9UvyjHEZbhYscZXT6bsc794Jv1kC2rj0upra3zBOUPz-rSeVaQiOS4vA7th2GlvOCQhpkVqHyvZXuoG8AhS17ZyMWl9ZPtzhrE5Ql14w0Au3pmnj6p8zhZslDHXbLeejV0PC314yexqdpbXS6lB72ovzNGUgu30t3Va5sQFbb18PyRzEtI2JOzvGC0TlN6w4n8o3aXQ7rwurkqx00fuzf5nQpOssfO3EFtxIIOT-ndzsM0pDZgh4l6QBXqz4O20Q",
|
||||
"refresh_token": "f876c11eb2cd221151096406ccd8878879b5bc3ba32822845674e117964c54b4",
|
||||
"token_type": "Bearer",
|
||||
"expires_in": 900
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
```text
|
||||
permission项你是推荐数据库迁移的方式新增吗?permission项的管理的最佳方式是什么?
|
||||
```
|
||||
Reference in New Issue
Block a user