4. 权限模型核心组件

ThingWorx 的权限模型不是单一开关,而是由用户(User)、用户组(User Group)、组织(Organization)、角色(Role)以及权限(Permission)五类对象共同构成的授权体系。理解它们各自在 Composer 界面中的位置、在 REST API 中的资源路径,以及彼此之间的引用关系,是后续做多租户隔离和最小权限治理的前提。

五类核心对象及其职责

用户是权限的最终承载者,代表一个可登录的账号。在 Composer 中通过 Security → Users 进入,关键字段包括用户名、密码、所属组织、所属用户组、是否启用、是否管理员。用户本身不直接持有权限,权限通过“用户组 + 组织”间接获得。

用户组是权限分配的主要载体,位于 Security → User Groups。一个用户组可以包含多个用户,也可以被授予多个角色。把权限绑在用户组而非单个用户上,是避免逐人维护的关键做法。

组织是租户隔离的边界,位于 Security → Organizations。每个用户必须且只能属于一个组织;组织之间默认互相不可见。多租户场景下,通常一个客户对应一个组织,组织名往往与租户标识一致。

角色是权限的集合,位于 Security → Roles。角色把“能做什么”抽象出来,例如只读、编辑、管理三类。角色可被授予用户组,也可被授予组织,从而形成“谁在什么范围内拥有什么能力”的组合。

权限是角色内部的最小粒度条目,通常以“资源类型 + 操作”的形式出现,例如 Thing:Read、Thing:Write、Application:Invoke。角色定义界面中通过勾选这些条目完成授权。

ThingWorx 权限模型:对象、界面入口与授权链路 用户 User Security → Users /Thingworx/Users 账号 · 密码 · 启用状态 用户组 User Group Security → User Groups /Thingworx/UserGroups 权限分配的主要载体 组织 Organization Security → Organizations /Thingworx/Organizations 租户隔离边界 角色 Role Security → Roles /Thingworx/Roles 权限集合 · 可复用 权限 Permission 角色定义界面勾选 Thing:Read / Write Application:Invoke 加入 归属 授予角色 包含 组织级授权 授权链路: 用户 → 加入用户组 → 用户组被授予角色 → 角色包含权限条目 → 在所属组织范围内生效 多租户要点:组织决定“看得到谁”,用户组与角色决定“能做什么”,两者叠加才是最终有效权限

操作界面:从入口到授权完成

在 Composer 中完成一次标准授权,通常按以下顺序操作。以“为租户 A 的运维人员开放设备只读权限”为例:

  1. 进入 Security → Organizations,新建组织 TenantA,记录其名称,后续用户归属时使用。
  2. 进入 Security → Roles,新建角色 TenantA_Viewer,在权限列表中勾选 Thing:Read、ThingTemplate:Read、Application:Invoke,保存。
  3. 进入 Security → User Groups,新建用户组 TenantA_Ops,在角色页签中把 TenantA_Viewer 授予该组。
  4. 进入 Security → Users,新建用户 ops_a01,组织选择 TenantA,用户组选择 TenantA_Ops,设置初始密码并启用。
  5. 用 ops_a01 登录,尝试读取一个属于 TenantA 的 Thing,应成功;尝试读取 TenantB 的 Thing,应被拒绝。这一步是验证授权是否按预期生效的关键。
角色与用户组是多对多关系:一个角色可授予多个用户组,一个用户组也可持有多个角色。最终权限是这些角色的并集,因此新增角色只会扩大权限,不会覆盖已有权限。

REST API:把界面操作变成可编排的调用

ThingWorx 的权限对象都通过 /Thingworx/ 下的 REST 资源暴露。调用时需要携带 appKey 或使用管理员会话,并设置 Content-Type: application/json。下面给出与界面操作一一对应的示例请求,参数为教学示例,实际使用时请替换为环境中的真实值。

# 1. 创建组织
POST /Thingworx/Organizations
Content-Type: application/json
{"name": "TenantA", "description": "租户A隔离边界"}

# 2. 创建角色并授予权限
POST /Thingworx/Roles
{"name": "TenantA_Viewer", "description": "租户A只读角色"}
PUT /Thingworx/Roles/TenantA_Viewer/Permissions
{"permissions": ["Thing:Read", "ThingTemplate:Read", "Application:Invoke"]}

# 3. 创建用户组并绑定角色
POST /Thingworx/UserGroups
{"name": "TenantA_Ops", "description": "租户A运维组"}
PUT /Thingworx/UserGroups/TenantA_Ops/Roles
{"roles": ["TenantA_Viewer"]}

# 4. 创建用户并归属组织与用户组
POST /Thingworx/Users
{"name": "ops_a01", "password": "示例初始密码",
 "organization": "TenantA", "userGroups": ["TenantA_Ops"], "enabled": true}

查询类接口同样重要。例如 GET /Thingworx/Users/ops_a01 可返回该用户的组织与用户组;GET /Thingworx/Roles/TenantA_Viewer/Permissions 可核对角色实际持有的权限条目。在做权限审计时,建议先拉取用户列表,再逐个展开其用户组与角色,最后汇总权限并集,而不是只看单个角色定义。

常见配置陷阱与判断依据

第一,用户创建后若未指定组织,可能落入默认组织,导致跨租户可见,这是多租户场景下最需要检查的字段。第二,角色权限勾选后必须保存并确认返回成功,否则用户组绑定的是一个空角色。第三,用户组与角色的绑定关系变更后,已登录用户的会话可能仍持有旧权限,需要重新登录或等待会话刷新。第四,判断授权是否生效,最直接的方式是用目标账号实际访问目标资源,观察返回是 200 还是 403,而不是仅凭界面配置推断。

不要用管理员账号去验证普通用户的权限,管理员通常绕过常规权限检查,验证结果会失真。务必使用与目标用户组一致的测试账号。