接口与响应字段
新版菜单模型里,业务侧不需要手动创建 apiBinding。你只要把 api:* 资源配置到页面默认接口或按钮操作上,permission-core 会在保存时自动生成内部接口契约,并把它用于角色菜单授权、Vext 路由守卫和响应字段裁剪。
这页只回答三件事:
- 页面打开时默认调用哪些接口。
- 页面按钮点击时调用哪些接口,或者只是纯前端按钮权限。
- 某个接口响应里哪些字段需要按角色授权后才能返回。
如果你只想先知道“我该用哪个方法”,看这张表就够了:
使用前提
逐项配置接口和字段前,需要先有菜单配置、菜单和页面:
orders-list 是创建页面时写入的 view.id,不是 loadApis.add() 临时生成的名字。这个 ID 在同一套菜单配置内必须唯一;创建方式见管理菜单里的 menus.views.create() 示例。
完整流程通常是:
如果要让某个用户实际生效,还要在角色授权后通过 userRoles.assign() 或 userRoles.set() 把角色绑定给用户。
如果配置、页面或按钮还不存在,menus.loadApis.add()、menus.actions.create()、menus.responses.set() 会在预览或执行阶段失败。
页面默认接口
页面默认接口表示:用户打开某个页面时,这个页面需要调用的后端接口。
逐项配置时,对应 menus.loadApis.add() 的 input.resource。如果你使用高级的配置即代码入口,同一含义对应 load.resource;本页先讲后台逐项管理 API。
例如订单列表页打开时会请求:
就把它登记为 orders-list 页面的 load API:
这段代码的意思是:
把
GET /api/orders登记为admin配置中orders-list页面的默认加载接口。
参数说明:
操作者和请求 ID 已在 pc.scope(scope, defaults) 里绑定;单次调用只有在需要覆盖默认值时才传 options。
保存成功后,你不需要关心内部快照结构;只要理解这条记录会落在 orders-list 页面的加载接口里,也就是等价于配置里的 views[].load[].resource = 'api:GET:/api/orders'。
这条 load 会影响三处:
接口资源不需要写 action: 'invoke'。loadApis.add() 会自动把 api:GET:/api/orders 编译成 invoke + api:GET:/api/orders。
路径中有参数时,使用路由模板:
不要把具体业务 ID 写进资源:
页面按钮和操作
按钮或操作表示:用户在页面里点击某个动作,例如导出、审核、删除、打开详情。
逐项配置时,对应 menus.actions.create() 的 input.resource。如果你使用高级的配置即代码入口,同一含义对应 actions[].resource。
如果按钮会调用后端接口,使用 api:*:
这段代码的意思是:
在
orders-list页面上创建一个“导出订单”按钮。用户有这个按钮权限时,才应该能看到或点击它;如果按钮调用后端,后端还要校验invoke + api:POST:/api/orders/export。
如果按钮只是纯前端能力,不调用后端接口,使用 ui:button:*:
两类按钮的区别:
如果按钮只是打开弹窗,而弹窗里再请求接口,推荐把弹窗建成一个 dialog 或 drawer view,再给这个 view 配置自己的 load API。这样权限含义更清楚:
响应字段配置
响应字段配置回答的是:
这个接口返回的 DTO 里,哪些字段需要变成可授权字段?
注意区分两件事:
也就是说,配置响应字段不等于用户已经能看到字段。角色没有字段授权时,字段仍会被裁剪。
响应字段挂在哪个接口上
menus.responses.set() 里的 owner 只是告诉系统:“这组字段属于哪一个接口响应”。新手优先按页面来源选择 load 或 action,别一开始就用 api。
页面默认接口的字段配置:
这段代码的意思是:
api:GET:/api/orders返回分页数据,真正要裁剪的是items中每一行;total是分页总数,保留但不参与字段授权;orderNo/status/amount是可以分配给角色的字段。
这些普通新增/设置操作会自动完成内部预览并提交。管理端如果想先展示影响,可以改用对应的 previewAdd()、previewCreate() 或 previewSet(),确认后再带 expected/previewToken 执行。
参数说明:
保存后,这组字段会挂到 api:GET:/api/orders 的 items 响应目标上。后面给角色授权时,就从这里声明过的 orderNo/status/amount 里选择。
数组形式和对象形式
在 MenuConfigInput.load[].response 或 actions[].response 里,可以直接写数组:
但在 menus.responses.set() 里,response 使用对象形式。即使没有 target,也要写成:
如果接口返回分页结构:
推荐写:
不要把敏感业务字段放进 preserve,因为 preserve 不参与字段授权。
授权响应字段
声明字段之后,还要给角色授权字段。下面表示:
order-operator可以进入订单列表页,可以调用页面默认接口和按钮接口,但订单列表接口只返回orderNo和status。
fields 必须来自前面已经声明过的响应字段。分页或嵌套响应建议写 target,例如 items 或 data.items;同一个接口存在多个响应目标时,不写 target 会因为目标不明确而被 preview 拒绝。
默认不会自动全选响应字段。如果确实要给某角色全部字段,必须显式设置:
后端裁剪响应
响应字段必须在后端返回前裁剪,不应该只靠前端隐藏。
手写框架时,推荐把接口入口鉴权和响应字段裁剪分开写:
如果当前用户只有 orderNo 和 status 字段权限,projected.data 接近:
职责边界:
filterResponse() 内部也会检查当前用户是否能 invoke 该 API;但业务接口仍建议先使用 subject.assert() 或框架守卫保护入口,这样失败点更清晰。
使用 Vext 插件时,受 permission: true 保护的路由可以自动做接口鉴权和响应字段投影;手写业务代码也可以显式调用 req.auth.permission.filterResponse()。详见Vext 插件。
未配置响应字段时会怎样
- 如果某个 API 没有配置
response,filterResponse()在接口权限通过后会返回原始 payload。 - 如果某个 API 配置了
response,但当前用户没有字段授权,则只会保留preserve中声明的结构字段。 - 如果接口包含敏感字段,应该配置
response并通过角色授权显式分配字段。
同一个接口被多个页面复用
同一个 apiResource 可以被多个页面或按钮复用,但响应结构需要兼容。
例如这些通常可以合并:
但如果同一个接口在不同页面声明了不同响应结构,例如一个是 target: 'items',另一个是 target: 'data.rows',预览可能会拒绝。遇到这种情况,优先考虑拆成不同 API,或者统一响应结构。
高级:配置即代码与批量导入
本页主线是后台逐项管理 API。如果你要从插件、CI/CD 或配置文件一次性导入整套菜单,请看菜单配置即代码与批量导入。
等价关系只有一条:MenuConfigInput.load[].resource 对应 menus.loadApis.add(),MenuConfigInput.actions[].resource 对应 menus.actions.create(),MenuConfigInput.load[].response 或 MenuConfigInput.actions[].response 对应 menus.responses.set()。
常见误区
精确字段约束见配置接口与响应字段 API,完整流程见管理菜单和角色菜单授权。