# permgen-for-goctl

goctl 插件，配合 [permlib](https://code.clickto.dev/weiym/permlib) 使用，自动从 go-zero 的 `.api` 文件中提取权限声明，生成 `internal/perms/perms.go`。

## 作用

产品端开发者在 `.api` 文件中通过 `@doc` 和 struct tag 声明权限，permgen 在代码生成时自动：

1. 收集所有接口的 `api:*` 权限 code，并自动生成配对的 `data:*` 权限
2. 收集请求/响应结构体中的字段级权限（`perm` tag）
3. 生成路由-权限映射表和字段-权限映射表
4. 输出 `internal/perms/perms.go`，供 `serviceContext` 注册到 permlib Engine

## 编译

```bash
git clone https://code.clickto.dev/weiym/permgen-for-goctl.git
cd permgen-for-goctl
go build -o permgen .
```

将编译产物 `permgen` 放到 `PATH` 可访问的目录，例如：

```bash
mv permgen /usr/local/bin/permgen
```

## 使用

在产品项目根目录执行：

```bash
goctl api go -api your.api -dir . --plugin permgen
```

执行后会在 `internal/perms/perms.go` 生成如下内容：

```go
// Code generated by permgen. DO NOT EDIT.

package perms

import "code.clickto.dev/weiym/permlib"

var Perms = []permlib.PermDecl{ ... }
var RoutePerms = []permlib.RoutePermDecl{ ... }
var FieldPerms = map[string]permlib.FieldPermMap{ ... }
```

在 `serviceContext` 中注册：

```go
engine.RegisterPerms(perms.Perms)
engine.RegisterRoutePerms(perms.RoutePerms)
engine.RegisterFieldPerms(perms.FieldPerms)
```

## api 文件写法

### 接口权限

在 `@doc` 中通过 `perm` 字段声明接口权限 code：

```text
@doc (
    summary: "创建用户"
    perm:    "api:user:create"
)
@handler CreateUser
post /user/create (CreateUserReq) returns (CreateUserResp)
```

- 没有 `perm` 声明的接口视为公开接口，不做权限检查
- `api:user:create` 会自动生成配对的 `data:user:create`

### 字段权限

在请求/响应结构体的字段上通过 `perm` tag 声明字段级权限：

```text
type CreateUserReq {
    Username string `json:"username"`
    Email    string `json:"email" perm:"data:user:email:write"`
    Salary   int64  `json:"salary" perm:"data:user:salary:write"`
}

type UserListItem {
    Username string `json:"username"`
    Email    string `json:"email" perm:"data:user:email:read"`
    Salary   int64  `json:"salary" perm:"data:user:salary:read"`
}
```

- `write` 权限：用户无权时，字段从请求体中移除（或拒绝请求，取决于 `FieldWriteMode`）
- `read` 权限：用户无权时，字段从响应体中自动移除
- 没有 `perm` tag 的字段不受控制，始终放行
