> **本文回答**：基于 RBAC 的后台权限 + 前端图形隐藏/密码保护/accessKey 分发。

## 一、后台角色（RBAC）

默认内置三种：

| 角色 | 权限（默认 policy.conf） |
|---|---|
| `root` | 最高权限：`/*` 全放行无 deny（含切片、删除 sys_ 图、后台配置） |
| `admin` | 一般管理：`/*` 放行，但 deny `updatemap/sys_*`、`renamemap/sys_*`、`deletemap/sys_*`、`deletestyle/sys_*`、`slicelayer/*`、`*RegCode`、`/client_*`、`/api/v1/service/workspace*` |
| `guest` | ⚠️ 默认策略 **deny 全部 `/api/v1/*`**——不是"只读"，是"不可访问业务 API"（仅能过 `/version`/`/heart` 等中间件前路由）。想让 guest 只读需在 `data/auth/policy.conf` 里自定义放行只读命令 |

不同角色对应不同 token（`accessToken`）。默认三枚演示 token：`root1`/`admin1`/`guest1`（服务端生成）；自定义角色与策略：`data/auth/policy.conf`（casbin `priority` 模型，数字小者先判，deny 优先于 allow）。

## 二、图形级权限

### 隐藏图

`mapid` 以 `ns_` 开头：对非 root 角色的 token 不可见（`listMaps` 不返回、云端管理平台不显示），需要知道 mapid 才能打开；root 仍可列出。

```js
await svc.openMap({ mapid: "ns_sensitive_001", mapopenway });
```

### 密码保护

上传时：

```js
await svc.openMap({
  mapid, fileid,
  secretKey: svc.pwdToSecretKey("P@ssw0rd"),
  mapopenway
});
```

云端管理平台也可"操作 → 设置密码"。

## 三、三种 Key 的能力

| Key | 作用 | 分发 |
|---|---|---|
| **superKey** | 超级权限：重置任意图密码、改 secretKey、全量访问 | 仅后台管理员持有，**不要给前端** |
| **secretKey** | 单图最高权限（可删、改版本） | 用户自己保留，不要分发 |
| **accessKey** | 单图访问权限（只读、不能改） | 可放前端、可发给他人 |

权限比较：`superKey > secretKey > accessKey`。

## 四、获取和使用 accessKey

1. 云端管理平台 → 该图操作菜单 → "获取 accessKey"。
2. 代码中：

```js
const svc = new vjmap.Service(URL, TOKEN);
svc.addAccessKey("akxxxxxxxxxxxxxxxx");         // 多图逐个调用加入内部 Set（上限 100 个）
svc.addAccessKey("akyyyyyyyyyyyyyyyy");
await svc.openMap({ mapid: "protected_map", mapopenway });
// 注：addSecretKey("ak" 开头的 18 位串) 会自动转给 addAccessKey
// addSecretKey 对 <16 字符的输入会先 pwdToSecretKey 哈希再存——
//   svc.addSecretKey("short") 后 Set 里存的是哈希值，has("short")=false。
//   secretKeys 上限 100 个，超出时剔除最早的一条（LRU）。
```

这样就不会弹密码框。

## 五、自动弹密码回调

```js
await svc.openMap({
  mapid,
  mapopenway,
  cbInputPassword: async ({ mapid, tryPasswordCount }) => {
    if (tryPasswordCount > 3) return "";
    return new Promise(resolve => {
      myCustomDialog.show("请输入密码", resolve);
    });
  }
});
```

参数 `tryPasswordCount` 大于 3 时返回空字符串中止。

## 六、工作区级隔离

工作区之间数据不共享。给不同项目、租户使用不同 workspace 能最简单地隔离：

```js
svc.switchWorkspace("tenantA");
// 访问只会看到 tenantA 的数据
```

后台可以给每个工作区分配独立的 token 范围。

## 七、前端安全建议

1. **不要把 Token 硬编码**：生产环境让后端生成 2–24 h 短 token。
2. **secretKey 不入 git**：使用 `svc.pwdToSecretKey(密码)` 实时算，或从服务端下发临时 secretKey。
3. **CORS**：`*.vjmap.com` 外的前端域名需后台 whitelist。
4. **HTTPS**：生产必须 HTTPS，否则 Token 易被中间人截获。
5. **敏感实体**：如果某些实体不希望前端能查到，建议走后端代理 + 投影（返回只经过筛选的数据），不直接把 `conditionQueryFeature` 暴露给浏览器。

## 八、常见坑

1. **admin 删 sys_ 开头的图失败** → 这是故意限制；用 root 或改名。
2. **`accessKey` 失效** → 本身没有过期时间；但重置 accessKey（`cmdResetAccessKey`）或改密码后旧 ak 作废——`openMap` 带内返回 `{status:403, error:"no permission to access this map…"}`，其他命令为 HTTP 403（不是 401）。
3. **隐藏图 URL 分享 / 截图** → URL 上含 token 时小心泄露。可用后端中转。
4. **混用 secretKey + accessKey** → 后端按 "最高可用 key" 判断；不会出错但别把 secretKey 泄漏。
