Skip to content

不使用空间的应用 ​

面向服务本身就是一个被多个租户使用的应用,并且权限通过角色授予用户的团队。不需要空间:一切都发生在默认空间。本页从路由映射到令牌搭建应用 wms,文档和配置都能运行,并用测试套件检查。模型见模型。

你需要什么 ​

不使用空间的应用
依赖快速开始里的那些;文档需要在运行时修改时再加 cosec-control
配置cosec.jwt.secret;cosec.authorization.scope.app-id: wms;cosec.authorization.routes.location: classpath:cosec-routes.json
文件服务里的 cosec-routes.json;发布到 Redis 的 platform.json 和 apps/wms.json
概念应用文档、目录、简写权限、系统角色、路由映射、绑定到应用的令牌
可以省掉空间:没有 spaced,没有 role@space,没有 CoSec-Space-Id

把路由映射为动作 ​

服务给自己的操作起名,权限就可以写 wms:warehouse.edit,而不是 PUT /warehouses/**:

json
{
  "service": "wms",
  "routes": [
    {
      "method": "GET",
      "path": "/warehouses",
      "action": "wms:warehouse.read",
      "resource": "warehouse"
    },
    {
      "method": "GET",
      "path": "/warehouses/{id}",
      "action": "wms:warehouse.read",
      "resource": "warehouse/{id}"
    },
    {
      "method": "PUT",
      "path": "/warehouses/{id}",
      "action": "wms:warehouse.edit",
      "resource": "warehouse/{id}"
    },
    {
      "method": "POST",
      "path": "/inbound/{id}/ship",
      "action": "wms:inbound.ship",
      "resource": "inbound/{id}"
    }
  ]
}

匹配路由的请求就是该路由在其资源上的动作;其他请求仍是路径上的 http:<METHOD>。路由映射会改变哪些语句适用,见按业务动作授权。

描述应用 ​

应用文档包含目录(写了 action 的条目就是权限)和系统角色:

json
{
  "schema": 2,
  "revision": 1,
  "publishedAt": "2026-11-01T08:00:00Z",
  "catalog": {
    "groups": [
      {
        "name": "Warehouse",
        "permissions": [
          {
            "id": "warehouse.read",
            "name": "Read warehouses",
            "action": "wms:warehouse.read"
          },
          {
            "id": "warehouse.edit",
            "name": "Edit warehouses",
            "action": "wms:warehouse.edit"
          },
          {
            "id": "inbound.ship",
            "name": "Ship inbound orders",
            "action": "wms:inbound.ship",
            "resource": "inbound/{id}"
          }
        ]
      }
    ]
  },
  "roles": [
    {
      "id": "clerk",
      "name": "Clerk",
      "description": "Looks things up",
      "permissions": [
        "warehouse.read"
      ]
    },
    {
      "id": "manager",
      "name": "Manager",
      "permissions": [
        "warehouse.read",
        "warehouse.edit",
        "inbound.ship"
      ]
    },
    {
      "id": "admin",
      "name": "Administrator",
      "permissions": "*"
    }
  ]
}
  • 每个带 action 的条目就是权限 perm:wms/<id>:一条允许该动作和 resource 的 ALLOW 语句。不需要手写策略(简写权限)。
  • 角色列出它持有的权限。"*" 是目录定义的所有权限,所以角色会随目录增长;目录变更的差异和审批会显示新增的授权。
  • 这个分组不是 spaced,所以每个权限在默认空间生效,而这正是此应用唯一的空间。
  • 这些角色对每个租户生效。租户需要自己的角色时再加一个:系统角色与自定义角色。

平台文档 ​

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
            ]
          }
        }
      ]
    }
  ],
  "bindings": [
    {
      "id": "login",
      "subject": "*",
      "app": "*",
      "space": "*",
      "policy": "login"
    },
    {
      "id": "control-api",
      "subject": "*",
      "app": "*",
      "space": "*",
      "policy": "control-api"
    }
  ]
}

它只放行登录路径和控制 API 的路径。应用允许的一切都来自它自己的文档、通过角色授予,所以这里没有出现 wms。

配置服务 ​

yaml
cosec:
  jwt:
    secret: ${COSEC_JWT_SECRET}
  authorization:
    scope:
      app-id: wms
    routes:
      location: classpath:cosec-routes.json

scope.app-id 让 wms 成为宿主的应用:服务只接受为 wms 签发的令牌,并为带角色的请求读取 wms 文档。它是服务所服务的应用,绝不是客户端说了算的东西。

发布,并为应用签发令牌 ​

按快速开始的方式发布文档,report 里列出两个文件:

bash
cd documents
{ printf '{"accepted":true,"outputSha256":{'; sep=""
  for f in platform.json apps/wms.json; do
    printf '%s"%s":"%s"' "$sep" "$f" "$(shasum -a 256 "$f" | cut -d' ' -f1)"; sep=","   # Linux: sha256sum
  done; printf '}}\n'; } > report.json
cosec-migrate publish --to-redis redis://localhost:6379 --in .

登录时说明令牌是为哪个应用签发的,以及用户在其中持有的角色:

kotlin
TokenSubject(id = user.id, app = "wms", tenant = user.tenant, roles = setOf("clerk"))

为其他应用或不为任何应用签发的令牌,会被这个服务拒绝(应用)。

验证 ​

wiki/examples/app 里的场景在每次构建时对这些文档运行:

请求令牌结果
GET /warehouses/7角色 clerk200:warehouse.read
PUT /warehouses/7角色 clerk403:clerk 没有 warehouse.edit
POST /inbound/42/ship角色 manager200
PUT /warehouses/7角色 admin200:"*"
GET /warehouses/7无角色403
GET /warehouses/7,CoSec-Space-Id: wh-01角色 clerk403 scope-rejected:令牌没有列出这个空间
GET /warehouses/7角色 clerk,为 pos 签发403 scope-rejected

用 cosec-testkit 以同样方式测试你自己的文档(测试决策)。

之后修改 ​

新增权限就是一个目录条目,通常还要在某个角色里加一行。通过控制面、用 (platform) 租户的主体修改应用文档,见之后修改文档:putCatalog 和 putRole 操作,或 POST /documents/app:wms:apply 提交整份文档。变更检查通过之前不会发布,并且会显示它给每个角色增加了什么。

出问题时 ​

  • 所有请求都是 503:还没有平台文档,或应用文档无法编译(故障排查)。
  • 403 scope-rejected:令牌的应用不是 wms(scope-rejected)。
  • 应该放行的角色得到 403:用解释决策问一问决策原因。

**下一步:**让租户添加自己的角色,见系统角色与自定义角色。

基于 Apache License 2.0 发布