@engage/bff 是为了让后端服务快速接入 engage 平台而提供的一个 npm 包。提供的能力有:

  1. 对其他应用请求本应用的 openApi 请求,验证签名、解密参数,转发给后端或自定义函数处理,处理完成后加密结果返回请求方。
  2. 对本应用请求其他应用的 openApi 请求, 加密参数,转发给其他应用,结果返回后解密结果返回给请求方。
  3. 对 api 请求,验证用户是否正常登录、对请求 api 是否有访问权限。如果没有,返回401,如果有,将请求转发给其他服务或自定义函数处理。
  4. 根据 token 获取用户信息,并将用户信息转发给后端。
  5. 提供应用校验 /open-api/v1/identify 接口
  6. 创建 api 和 openApi接口

# 安装

通过 yarn add @engage/bff --registry=http://registry.npm.gridsum.comnpm i @engage/bff --registry=http://registry.npm.gridsum.com 命令安装

# 使用

import bff from '@engage/bff';

const server = bff.createBffServer({...});

server.start();

# createBffServer

创建一个 express 对象,该对象上集成了接口转发、用户信息集成、openApi 验证签名、解密参数、加密结果的中间件。

# 入参

 {

  server: {

    port: 8080, // 应用开放端口,默认8080,number 类型

    apiPrefix: '', // 对外接口统一前缀,如 '/wechat',必填,string 类型

    platformHost: '', // 获取用户信息、用户可访问 api 接口域名,如'https://alpha-engage.gridsumdissector.com/',必填,string 类型

    cors: { // 跨域

      origin: true, // cors origin,详细配置参见 https://github.com/expressjs/cors#configuration-options,默认为true

      maxAge: 2592000, // 预检请求有效期,单位 s 。默认30天,number 类型

      methods: ['POST'], // 跨域接受的请求类型,默认 ['POST'],array<string> 类型

    },

  },

  clientConfig: { // 应用配置相关

    appId: '', // 应用 id ,必填,string 类型

    clientId: '', // 应用的 clientId ,必填,string 类型

    clientSecret: '', // 应用的 clientSecret ,必填,string 类型

    clientSign: '', // 应用的 clientSign ,必填,string 类型

  },

  redisOption: { // 应用 redis 配置,主要用来缓存用户信息,用户可访问 api 列表

    password: '', // redis 连接密码,必填,string 类型

    keyPrefix: '', // 所有 key 的前缀

    mode: 'standalone', // 支持单点(standalone)、哨兵(sentinel),必填,string 类型

    standalone: { // 单点模式时必填

      host: '', // 必填,string 类型

      port: 8090, // 必填,string 类型

    },

    sentinel: { // 哨兵模式必填

      name: '', // 主从集群的名称,必填,string 类型

      endpoints: [], // 哨兵地址列表,必填,array<string> 类型

    },

  },

  redis: null, // redis 对象,和 redisOption 二选一即可,支持通过 ioredis 创建的连接对象

  internalOpenApiProxy: { // 当后端服务通过 BFF 请求其他应用的 openApi 时需要配置

    whiteList: ['10.200.50.123', '10.0.0.0/8'], // 访问 /internal-openapi-proxy 接口的白名单 IP 或 IP 段,当不填写或为空数组时,所有 IP 可正常访问该接口。否则,来源IP需要在白名单IP中才可访问。

  },

  apiAuth: { // 供前端调用的 API 权限控制,前缀匹配

    public: ['/api/v1/test/add'], // public 接口,未登录或已登录的用户均可访问

    internal: ['/api/v1/test/delete'], // internal 接口,只有登录用户可以放嗯

  },

  proxyRules: [ // 接口转发规则
    {

      api: '/open-api/v1/xxx/xxx', // 前缀形式或完整 url ,比如/open-api/v1/bind 或 /open-api/v1,必填,string 类型,/open-api 表示提供给其他应用访问的接口前缀

      prefix: '/wechat', // 目标应用的路由前缀,配置后目标服务接收到的路由是 prefix + 请求 url ,如 api 配置为 /open-api/v1/add ,prefix 配置为 /wechat ,则 BFF转发的 url 为 /wechat/open-api/v1/add ,string 类型

      target: 'http://test.com/api', // target 表示向后台哪个地址转发,target 和 handler 只能且必须设置一个

      timeout: 120000, // 超时时间,单位 ms,默认2分钟, number 类型

    },
    {

      api: '/api/xxx/xxx', // 前缀形式或完整 url ,比如/user/add 或 /user,不以 /open-api 开头的表示提供给本应用内访问的接口,必填,string 类型

      handler(req) {}, // 不向后台转发,使用 BFF 内部处理的函数,支持 async,函数返回处理结果 json 对象。通过这种方式可增加自定义 api 和 openApi。function 类型。

    },

  ],
};

# 出参

express 实例,挂载了 start 方法。

# 使用

import bff from '@engage/bff';

const server = bff.createBffServer({...});

# server.start

启动 createBffServer 方法创建的实例,http 服务,端口号为 createBffServer 入参中的 server.port 。

# 入参

callbackFunction ,表示服务启动成功后的回调方法。

# 使用

import bff from '@engage/bff';

const server = bff.createBffServer({...});

server.start(()=>{ console.log('服务启动成功'); });

# 调用其他服务 openApi

使用 @engage/bff 提供的接口调用其他服务 openApi ,你无需再关心数据加密、结果解密,@engage/bff 全都帮你做好了。你只需要把你调用的 openApi 地址、请求的未加密 body 传给 @engage/bff ,@engage/bff 会帮你把 body 数据加密,并将请求和加密后的数据转发给你想请求的 openApi 地址。结果返回后,@engage/bff 会将结果解密然后返回给你。

# 接口路径

/internal-openapi-proxy ? method = 加密类型

# 使用

post http://xxx.com/internal-openapi-proxy?method=ENGAGE1-AES-HMAC

method 可选的值有 ENGAGE1-AES-HMACENGAGE1-HMAC ,不填时默认为 ENGAGE1-AES-HMAC 。然后在请求的 headers 中增加 engage-bff-target-openapi ,值为真实请求的 openApi 地址,如 https://xxx.com/open-api/v1/validate 。

body 中放请求原始 openApi 的未加密 body 数据。

# 调用本应用 openApi

使用 @engage/bff 转发请求本应用的 openApi,@engage/bff 会帮你验证签名,验证通过后,解密参数。解密后的数据格式如下:

{
  profileId: '',
  userId: '',
  data: {},
}

@engage/bff 对解密后参数会做两步处理:

  1. 将 profileId 、userId 信息放在 engage-common-info HTTP Header 中,格式如下:
{
  auth: {
    profileId: '',
    userId: '',
  },
  traceId: '', // 本次请求唯一标识
  dataScope: 'PROFILE',
}
  1. 将解密后数据中的 data 作为转发请求的 body 。

以上两步完成后,将请求转发给后端,结果返回后,@engage/bff 会帮你加密结果然后返回。

# 使用

proxyRules 按照如下格式配置即可。

  [{

  api: '/open-api/v1/xxx/xxx', // 前缀形式或完整 url ,必填,string 类型

  prefix: '/wechat', // 目标应用的路由前缀,配置后目标服务接收到的路由是 prefix + 请求 url ,string 类型

  target: 'http://test.com/api', // target 表示向后台哪个地址转发

  timeout: 120000, // 超时时间,单位 ms,默认2分钟, number 类型

  }]

# 调用本应用 api

使用 @engage/bff 转发请求本应用的 api,@engage/bff 会帮你验证用户登录是否有效,用户是否是有权限访问此 api 。如果有, @engage/bff 会把根据 token 获取到的用户信息放在 headers 的 engage-common-info 属性中,格式如下,auth 中属性详见 detail

{
  auth: {
    profileId: '',
    userId: '',
    userName: '',
    positionId: '',
    organizationId: '',
    subPositionIds: [],
    subOrganizationIds: '',
    email: '',
    language: '',
  },
  traceId: '', // 本次请求唯一标识
  dataScope: 'PROFILE',
}

header构造完成后,将请求转发给后端,然后将相应结果直接返回。

# 使用

proxyRules 按照如下格式配置即可。

  [{

  api: '/api/v1/xxx/xxx', // 前缀形式或完整 url ,必填,string 类型

  prefix: '/wechat', // 目标应用的路由前缀,配置后目标服务接收到的路由是 prefix + 请求 url ,string 类型

  target: 'http://test.com/api', // target 表示向后台哪个地址转发

  timeout: 120000, // 超时时间,单位 ms,默认2分钟, number 类型

  }]

# 增加 openApi 或 api 接口

支持增加 openApi 或 api 接口,proxyRules 按照如下格式配置即可。

  [{

  api: '/api/v1/xxx/xxx', // 前缀形式或完整 url ,必填,string 类型

  handler(req){ return {data : 'success'}}

  }]

# 应用校验 /open-api/v1/identify

使用 @engage/bff 包后,你的服务会天然具有应用校验接口。接口使用参见 detail