简单模式
面向要为一个服务、一个客户提供保护的开发者,或不需要应用、空间和业务动作名称的小型产品。简单模式是能运行的最小配置:一份平台文档,请求用 HTTP 方法和路径命名,不用路由映射。本页列出需要什么,给出一份可用的文档,并说明何时该往前走。
你需要什么
| 简单模式 | |
|---|---|
| 依赖 | 快速开始里的那些 |
| 配置 | spring.data.redis.* 和 cosec.jwt.secret。客户端直连服务时再加 cosec.authorization.remote-ip.max-trusted-index: 0。应用、空间、路由映射都不用配。 |
| 文件 | platform.json;用 cosec-migrate publish 写成第一个修订 |
| Redis | maxmemory-policy noeviction |
| 概念 | 平台文档、策略、语句、绑定给所有人("subject": "*")、http 命名空间、默认拒绝、拒绝优先、默认租户 (0) |
| 可以省掉 | 应用和空间、路由映射、目录、角色条目、边界、限流、影子窗口 |
每个请求都是 http:path:<path> 上的 http:<METHOD>。令牌不带租户,所以主体在默认租户 (0);不带应用,所以不读取任何应用文档。
文档
json
{
"schema": 2,
"revision": 1,
"publishedAt": "2026-11-01T08:00:00Z",
"policies": [
{
"id": "login",
"statements": [
{
"name": "login",
"effect": "allow",
"action": "http:POST",
"resource": "http:path:/auth/login"
}
]
},
{
"id": "control-api",
"statements": [
{
"name": "reach-the-control-api",
"effect": "allow",
"action": [
"http:GET",
"http:POST",
"http:DELETE"
],
"resource": "http:path:/cosec/control/v1/**",
"condition": {
"eq": [
"subject.authenticated",
true
]
}
}
]
},
{
"id": "public",
"statements": [
{
"name": "hello",
"effect": "allow",
"action": "http:GET",
"resource": "http:path:/hello"
}
]
},
{
"id": "members",
"statements": [
{
"name": "read-orders",
"effect": "allow",
"action": "http:GET",
"resource": "http:path:/orders/**",
"condition": {
"eq": [
"subject.authenticated",
true
]
}
}
]
},
{
"id": "admins",
"statements": [
{
"name": "admin-area",
"effect": "allow",
"action": "http:*",
"resource": "http:path:/admin/**",
"condition": {
"in": [
"admin",
"scope.roles"
]
}
}
]
},
{
"id": "no-delete",
"statements": [
{
"name": "orders-are-kept",
"effect": "deny",
"action": "http:DELETE",
"resource": "http:path:/orders/**"
}
]
}
],
"bindings": [
{
"id": "login",
"subject": "*",
"app": "*",
"space": "*",
"policy": "login"
},
{
"id": "control-api",
"subject": "*",
"app": "*",
"space": "*",
"policy": "control-api"
},
{
"id": "public",
"subject": "*",
"app": "*",
"space": "*",
"policy": "public"
},
{
"id": "members",
"subject": "*",
"app": "*",
"space": "*",
"policy": "members"
},
{
"id": "admins",
"subject": "*",
"app": "*",
"space": "*",
"policy": "admins"
},
{
"id": "no-delete",
"subject": "*",
"app": "*",
"space": "*",
"policy": "no-delete"
}
]
}public允许任何人GET /hello,无论是否登录;login对POST /auth/login同理。members允许已登录的调用方GET /orders/**。admins允许持有角色admin的主体访问/admin/**下的一切。简单模式里令牌的角色是默认空间的角色,所以scope.roles就是令牌的roles声明。授权请用scope.roles,不要用subject.roles,后者也会计入其他空间里的角色(条件中的角色)。no-delete对所有人禁止DELETE /orders/**。匹配的 DENY 胜过所有 ALLOW,admin也不例外。control-api允许任何已登录的调用方到达控制 API 的路径。控制面会以调用方的身份再授权每一步,所以这里开放的是路径,不是权限。没有它,你就再也无法通过控制面修改这份文档,见之后修改文档。
用户登录时签发带角色的令牌:
kotlin
TokenSubject(id = user.id, app = null, roles = setOf("admin"))验证
wiki/examples/simple/scenarios 里的场景在每次构建时用测试套件对这些文档运行:
| 请求 | 调用方 | 决策 |
|---|---|---|
GET /hello | 匿名 | Permit |
GET /orders/1 | 匿名 | Deny:401 |
GET /orders/1 | 已登录 | Permit |
DELETE /orders/1 | 角色 admin | Deny:DENY 获胜 |
GET /admin/users | 角色 admin | Permit |
GET /admin/users | 已登录,无角色 | Deny:403 |
很多角色
每个角色一个条件,超过几个就不好用了。默认租户和其他租户一样,可以放角色绑定:在平台文档里不绑定 admins,把绑定放进 tenants/(0).json(文件名要做 URL 编码,即 tenants/%280%29.json):
json
{
"schema": 2,
"revision": 1,
"publishedAt": "2026-11-01T08:00:00Z",
"bindings": [
{
"id": "editors-edit",
"subject": {
"role": "editor"
},
"app": "*",
"space": "*",
"policy": "editors"
},
{
"id": "admins-administer",
"subject": {
"role": "admin"
},
"app": "*",
"space": "*",
"policy": "admins"
}
]
}这里的角色绑定适用于持有该角色的主体;而这份文档里绑定给 "*" 的内容也适用于匿名调用方,因为它们同样属于 (0)。包含平台文档和场景的完整示例见 wiki/examples/simple-roles。
简单模式的限制
- 平台文档不能绑定角色。它由所有租户共用,写在那里的角色对所有租户意味着同一件事。请用上面的条件,或
(0)文档。 - 角色变更在用户下次登录时才生效,因为角色在令牌里(角色与空间)。
- 权限写成语句。想在控制台里列出权限、或按名称把权限授予角色,请换成应用文档:不使用空间的应用。
**下一步:**带权限和角色的应用,见不使用空间的应用。