173 lines
5.3 KiB
Markdown
173 lines
5.3 KiB
Markdown
|
|
# 任务012:补充权限校验
|
|||
|
|
|
|||
|
|
## 目标
|
|||
|
|
|
|||
|
|
为 cabinets.rs、projects.rs、organizations.rs 三个模块补充完整的权限校验。
|
|||
|
|
|
|||
|
|
## 问题描述
|
|||
|
|
|
|||
|
|
第二轮代码审查发现这3个模块的handler函数签名中缺少 `CurrentUser` 参数,导致无法进行权限校验。任何登录用户都可以访问这些敏感接口。
|
|||
|
|
|
|||
|
|
## 修复清单
|
|||
|
|
|
|||
|
|
### 1. 权限码定义
|
|||
|
|
|
|||
|
|
首先在权限表中添加缺失的权限码:
|
|||
|
|
|
|||
|
|
```sql
|
|||
|
|
-- 组织管理
|
|||
|
|
INSERT INTO permissions (code, name) VALUES ('org:view', '查看组织');
|
|||
|
|
INSERT INTO permissions (code, name) VALUES ('org:create', '创建组织');
|
|||
|
|
INSERT INTO permissions (code, name) VALUES ('org:edit', '编辑组织');
|
|||
|
|
INSERT INTO permissions (code, name) VALUES ('org:delete', '删除组织');
|
|||
|
|
|
|||
|
|
-- 项目管理
|
|||
|
|
INSERT INTO permissions (code, name) VALUES ('project:view', '查看项目');
|
|||
|
|
INSERT INTO permissions (code, name) VALUES ('project:create', '创建项目');
|
|||
|
|
INSERT INTO permissions (code, name) VALUES ('project:edit', '编辑项目');
|
|||
|
|
INSERT INTO permissions (code, name) VALUES ('project:delete', '删除项目');
|
|||
|
|
|
|||
|
|
-- 设备管理(补充)
|
|||
|
|
INSERT INTO permissions (code, name) VALUES ('device:edit', '编辑设备');
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. organizations.rs 修复
|
|||
|
|
|
|||
|
|
**文件:** `src/routes/organizations.rs`
|
|||
|
|
|
|||
|
|
**修改内容:**
|
|||
|
|
- 所有handler函数签名添加 `user: CurrentUser` 参数
|
|||
|
|
- 每个handler开头调用 `check_permission`
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
// 示例:获取组织列表
|
|||
|
|
#[get("/api/organizations")]
|
|||
|
|
async fn list_organizations(
|
|||
|
|
user: CurrentUser, // 新增
|
|||
|
|
pool: State<MySqlPool>,
|
|||
|
|
) -> Result<Json<Vec<Organization>>> {
|
|||
|
|
auth::check_permission(&user, "org:view")?; // 新增
|
|||
|
|
// ... 原有逻辑
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 示例:创建组织
|
|||
|
|
#[post("/api/organizations")]
|
|||
|
|
async fn create_organization(
|
|||
|
|
user: CurrentUser, // 新增
|
|||
|
|
pool: State<MySqlPool>,
|
|||
|
|
json: Json<CreateOrganizationRequest>,
|
|||
|
|
) -> Result<Json<Organization>> {
|
|||
|
|
auth::check_permission(&user, "org:create")?; // 新增
|
|||
|
|
// ... 原有逻辑
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**需要修复的端点:**
|
|||
|
|
- `GET /api/organizations` → `org:view`
|
|||
|
|
- `POST /api/organizations` → `org:create`
|
|||
|
|
- `PUT /api/organizations/:id` → `org:edit`
|
|||
|
|
- `DELETE /api/organizations/:id` → `org:delete`
|
|||
|
|
|
|||
|
|
### 3. projects.rs 修复
|
|||
|
|
|
|||
|
|
**文件:** `src/routes/projects.rs`
|
|||
|
|
|
|||
|
|
**修改内容:**
|
|||
|
|
- 所有handler函数签名添加 `user: CurrentUser` 参数
|
|||
|
|
- 每个handler开头调用 `check_permission`
|
|||
|
|
|
|||
|
|
**需要修复的端点:**
|
|||
|
|
- `GET /api/organizations/:org_id/projects` → `project:view`
|
|||
|
|
- `POST /api/organizations/:org_id/projects` → `project:create`
|
|||
|
|
- `PUT /api/projects/:id` → `project:edit`
|
|||
|
|
- `DELETE /api/projects/:id` → `project:delete`
|
|||
|
|
|
|||
|
|
### 4. cabinets.rs 修复
|
|||
|
|
|
|||
|
|
**文件:** `src/routes/cabinets.rs`
|
|||
|
|
|
|||
|
|
**修改内容:**
|
|||
|
|
- 所有handler函数签名添加 `user: CurrentUser` 参数
|
|||
|
|
- 每个handler开头调用 `check_permission`
|
|||
|
|
- `list_cabinets` 和 `get_cabinet` 需要额外验证用户是否有权访问该项目
|
|||
|
|
|
|||
|
|
**需要修复的端点:**
|
|||
|
|
- `GET /api/projects/:project_id/cabinets` → `device:view` + 项目权限验证
|
|||
|
|
- `POST /api/cabinets` → `device:create`
|
|||
|
|
- `PUT /api/cabinets/:id` → `device:edit`
|
|||
|
|
- `DELETE /api/cabinets/:id` → `device:delete`
|
|||
|
|
- `POST /api/cabinets/:id/regenerate-auth` → `device:edit`
|
|||
|
|
- `GET /api/cabinets/:id` → `device:view` + 项目权限验证
|
|||
|
|
- `GET /api/cabinets/options` → `device:view`
|
|||
|
|
- `GET /api/cabin-boards/options` → `device:view`
|
|||
|
|
- `GET /api/compartments/options` → `device:view`
|
|||
|
|
|
|||
|
|
**项目权限验证逻辑:**
|
|||
|
|
```rust
|
|||
|
|
// 验证用户是否有权访问指定项目
|
|||
|
|
async fn check_project_access(
|
|||
|
|
user: &CurrentUser,
|
|||
|
|
pool: &MySqlPool,
|
|||
|
|
project_id: i64,
|
|||
|
|
) -> Result<()> {
|
|||
|
|
if user.role_level >= 2 {
|
|||
|
|
// 总管理员可访问所有项目
|
|||
|
|
return Ok(());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
if let Some(org_id) = user.organization_id {
|
|||
|
|
// 验证项目是否属于用户的组织
|
|||
|
|
let project: Option<(i64,)> = sqlx::query_as(
|
|||
|
|
"SELECT id FROM projects WHERE id = ? AND organization_id = ?"
|
|||
|
|
)
|
|||
|
|
.bind(project_id)
|
|||
|
|
.bind(org_id)
|
|||
|
|
.fetch_optional(pool)
|
|||
|
|
.await?;
|
|||
|
|
|
|||
|
|
if project.is_none() {
|
|||
|
|
return Err(AppError::Forbidden("无权访问该项目".into()));
|
|||
|
|
}
|
|||
|
|
} else {
|
|||
|
|
return Err(AppError::Forbidden("无组织关联".into()));
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
Ok(())
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 5. users.rs 修复(额外)
|
|||
|
|
|
|||
|
|
**文件:** `src/routes/users.rs`
|
|||
|
|
|
|||
|
|
**修改内容:**
|
|||
|
|
- `list_users` 添加组织隔离,企业管理员只能看到本组织的用户
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
// 修改 list_users 查询
|
|||
|
|
let users = if user.role_level >= 2 {
|
|||
|
|
// 总管理员看所有用户
|
|||
|
|
sqlx::query_as("SELECT * FROM users")
|
|||
|
|
.fetch_all(&pool)
|
|||
|
|
.await?
|
|||
|
|
} else if let Some(org_id) = user.organization_id {
|
|||
|
|
// 企业管理员只看本组织用户
|
|||
|
|
sqlx::query_as("SELECT * FROM users WHERE organization_id = ?")
|
|||
|
|
.bind(org_id)
|
|||
|
|
.fetch_all(&pool)
|
|||
|
|
.await?
|
|||
|
|
} else {
|
|||
|
|
vec![] // 无组织用户看不到任何人
|
|||
|
|
};
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
## 质量约束
|
|||
|
|
|
|||
|
|
1. 完成代码后执行 `cargo check` + `cargo clippy`,零报错零警告
|
|||
|
|
2. 分层拆分,单函数≤80行,命名语义化,完整注释
|
|||
|
|
3. 所有外部IO/网络请求异常捕获,禁止裸panic
|
|||
|
|
4. 分支逻辑全覆盖,不遗漏兜底分支
|
|||
|
|
5. 常量抽离,不使用废弃API
|
|||
|
|
6. Rust内存安全,合理管理所有权,禁用unsafe无合理理由
|
|||
|
|
7. 修复后重新运行 `cargo test`(如有测试)确保无回归
|