@engage/bff 是为了让后端服务快速接入 engage 平台而提供的一个 npm 包。提供的能力有:
- 对其他应用请求本应用的 openApi 请求,验证签名、解密参数,转发给后端或自定义函数处理,处理完成后加密结果返回请求方。
- 对本应用请求其他应用的 openApi 请求, 加密参数,转发给其他应用,结果返回后解密结果返回给请求方。
- 对 api 请求,验证用户是否正常登录、对请求 api 是否有访问权限。如果没有,返回401,如果有,将请求转发给其他服务或自定义函数处理。
- 根据 token 获取用户信息,并将用户信息转发给后端。
- 提供应用校验 /open-api/v1/identify 接口
- 创建 api 和 openApi接口
# 安装
通过 yarn add @engage/bff --registry=http://registry.npm.gridsum.com
或 npm 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-HMAC 和 ENGAGE1-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 对解密后参数会做两步处理:
- 将 profileId 、userId 信息放在 engage-common-info HTTP Header 中,格式如下:
{
auth: {
profileId: '',
userId: '',
},
traceId: '', // 本次请求唯一标识
dataScope: 'PROFILE',
}
- 将解密后数据中的 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