charging-cabinet/tasks/012-permission-checks-supplement.md

173 lines
5.3 KiB
Markdown
Raw Normal View History

# 任务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`(如有测试)确保无回归