跳到主要内容

🔒 ONES 接口劫持

适用环境私有部署
能力废弃说明

此能力自2023年10月13号起已废弃。相关需求需要类似能力,请向开放平台提新的需求单。

要求

ONES
v3.6.0+

概述

有时候我们需要改变 ONES 系统中某些行为的表现,在某个行为前后增加一些操作或者替换行为本身来达到业务需求。插件可以通过接口劫持能力对 ONES 标准系统中所有对外开放的接口进行劫持,支持前置、后置和替换方式;

  • 替换:插件可以”替换“标准系统系统的某个接口,让插件能够对现有系统的某个请求进行完全的自定义处理。
  • 前置劫持:是指当请求进入标准系统时,未被处理前就会先被转发到插件,由插件对请求进行修改后,回传给标准系统并继续执行原先的逻辑。一般用于修改请求的参数,或对请求进行校验;
  • 后置劫持:是指当请求在 ONES 完成处理后,会发送通知给插件,插件此时可进行一些后置处理,但无法修改响应内容。

劫持替换都是比较底层的操作,可能对系统功能产生未知风险。一般只有在其它能力都不满足需求的情况下,才考虑使用接口劫持能力。

警告

该能力即将遗弃,不保证后续兼容性!

使用

使用须知

  1. 组织级别的接口和团队级别的接口的差别在于团队级别接口的 url 中包含有 /team/:teamUUID。对于同一个接口:组织级别接口只允许一个插件进行劫持;团队级别接口允许每个团队中都有一个插件进行劫持,但同个团队中只允许一个插件进行劫持。
  2. 在本地调试中,如果修改了插件配置文件config/plugin.yaml,需要运行 npx op invoke clear 并重新运行 npx op invoke run 指令才能使配置生效。

replace 接口替换

  • 请求流程

  • 配置示例

    在插件配置文件中的 apis 字段加上以下配置:

    apis:
    - type: replace #接口类型: replace:替换
    methods: #接口请求方式
    - POST
    url: /team/:teamUUID/online_page/:pageUUID/update_title #劫持接口url
    scope: wiki #project或wiki接口,没有该属性则默认为project
    function: jackFunc #名称与代码里的函数名保持一致
  • 添加处理方法

    该示例替换了 wiki 修改页面标题的接口,会将页面标题设置为"plugin title"

    import { fetchONES } from '@ones-op/node-fetch'
    import { Logger } from '@ones-op/node-logger'

    export async function jackFunc(
    request: PluginRequest<Record<string, any>>,
    ): Promise<PluginResponse> {
    Logger.info('replace success')
    let userUUID = ''
    let userToken = ''
    if (request.headers['Ones-User-Id'] != null) {
    userUUID = request.headers['Ones-User-Id']
    userToken = request.headers['Ones-Auth-Token']
    }
    Logger.info('url:', request.url)
    let response = await fetchONES({
    path: '/wiki' + request.url,
    method: 'POST',
    headers: {
    'Ones-User-Id': [userUUID],
    'Ones-Auth-Token': [userToken],
    },
    body: {
    title: 'plugin title',
    },
    root: false,
    })
    Logger.info(JSON.stringify(response, undefined, 2))
    if (response) {
    return response
    }
    return {
    body: {},
    }
    }
  • 注意事项

    接口请求参数需要注意以下几点:

    • 劫持的是 ONES API ,所以填写的 url 必须跟访问 ONES API 的 url 保持一致;

    • 确认被替换接口本身是 POST 请求还是 GET 请求;

    • 确认被替换接口请求头需要设置什么参数,请参考 ONES API 文档;

    • 插件使用 replace 能力的时候,如果对原有的劫持接口进使用 fetch、fetchONES、axios 请求时,请勿使用原有的请求头,一般只提取 UserID 和 UserToken,其次如果是多团队的环境下,使用 fetchONES 注意在请求头上加上【teamUUID】参数,避免插件出现 403 问题。

prefix 前置接口劫持

  • 请求流程

  • 配置示例

    在插件配置文件中的 apis 字段加上以下配置:

    apis:
    - type: prefix #接口类型: prefix:前置劫持
    methods:
    - POST
    url: /team/:teamUUID/online_page/:pageUUID/update_title
    scope: wiki
    function: prefixFunc
  • 添加处理方法

    该示例对 wiki 修改页面标题的接口进行前置劫持,在本次修改标题中加上后缀

    //prefix 前置接口劫持
    export async function prefixFunc(
    request: PluginRequest<Record<string, any>>,
    ): Promise<PluginResponse> {
    let body = request?.body as any
    let headers = request?.headers as any
    body.title = body.title + '-plugin'
    return {
    headers: headers,
    body: body,
    }
    }

suffix 后置接口劫持

  • 请求流程

  • 配置示例

    在插件配置文件中的 apis 字段加上以下配置:

    apis:
    - type: suffix #接口类型: suffix:后置
    methods:
    - GET
    url: /users/me
    scope: project
    function: suffixFunc
  • 添加处理方法

    该示例表示当接口完成处理之后,记录一些内容到suffix.txt文件中

    import { createFile, writeStrings } from '@ones-op/node-file'
    import { Logger } from '@ones-op/node-logger'

    export async function Install() {
    await createFile('./suffix.txt')
    Logger.info('[Plugin] Install')
    }
    //suffix hijacking
    export async function suffixFunc(
    request: PluginRequest<Record<string, any>>,
    ): Promise<PluginResponse> {
    Logger.info('suffix success')
    let body = request?.body as any
    await writeStrings('./suffix.txt', [JSON.stringify(request, undefined, 2)])
    return {
    // 可以返回任意 body
    body: {},
    }
    }

自定义 query 参数

支持带有自定义 query 参数的接口劫持,对于同一个 url,允许通过请求的 query 参数做不同的接口劫持方法处理。你可以在config/plugin.yaml中的apis字段内设置自定义的 query 参数, 所有对于该接口的请求如果带有这些设定好的参数则该请求被劫持,否则不劫持。

  • 劫持规则
  1. 一个接口只能由一个插件进行一种类型的接口劫持(prefix,replace,suffix),但允许一个接口定义不同的 query 参数,匹配不同的函数处理方法

  2. 自定义 query 参数为一个 key 和 value 都为 string 的 map,当对于该接口的请求中包含了 map 中的所有 key 和 value 则触发劫持

  3. 当一个请求满足多个带有自定义 query 参数的接口劫持规则时,按照config/plugin.yaml文件中 apis 声明的先后顺序优先匹配对应方法

  • 配置示例

    在插件配置文件中的 apis 字段加上以下配置:

    apis:
    - type: replace
    methods:
    - POST
    scope: project
    url: /users/me
    function: replaceFunc1
    query:
    k1: v1
    - type: replace
    methods:
    - POST
    scope: project
    url: /users/me
    function: replaceFunc2
    query:
    k2: v2
    • 请求 url: /users/me?k2=v2 命中: replaceFunc2

    • 请求 url: /users/me?k1=v1&k2=v2&k3=v3 按照声明顺序匹配,命中: replaceFunc1

    • 请求 url: /users/me 无命中,不进行接口劫持,走原处理逻辑

调试方式

  • 使用 curl 工具进行访问,以/users/me接口为例:

    curl --location --request GET 'https://yourhost/users/me' \
    --header 'Ones-User-Id: {user_uuid}' \
    --header 'Ones-Auth-Token: {user_token}' \
    --header 'Content-Type: application/json' \
    --data ''
  • 代码请求参数示例

    url:https://yourhost/users/me
    headers:
    Ones-User-Id:{user_uuid}
    Ones-Auth-Token:{user_token}
    ...
    method: GET