1
This commit is contained in:
89
api/controller_custom/proxy_api.js
Normal file
89
api/controller_custom/proxy_api.js
Normal file
@@ -0,0 +1,89 @@
|
||||
const swagger = require("../../_docs/swagger.json");
|
||||
const auth = require("../service/biz_auth_verify");
|
||||
const proxy = require("../service/biz_proxy_service");
|
||||
|
||||
function getRequestBody(ctx) {
|
||||
if (ctx.request && ctx.request.body && Object.keys(ctx.request.body).length > 0) {
|
||||
return ctx.request.body;
|
||||
}
|
||||
if (typeof ctx.getBody === "function") {
|
||||
return ctx.getBody() || {};
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
/**
|
||||
* 从请求中提取 Token
|
||||
* 支持 Authorization: Bearer xxx 和 query ?token=xxx
|
||||
*/
|
||||
function extractToken(ctx) {
|
||||
const authHeader = ctx.get("Authorization") || "";
|
||||
if (authHeader.startsWith("Bearer ")) {
|
||||
return authHeader.slice(7).trim();
|
||||
}
|
||||
return ctx.query.token || "";
|
||||
}
|
||||
|
||||
/**
|
||||
* 提取 swagger tags 第一项作为 feature 名(用于套餐功能点校验)
|
||||
*/
|
||||
function pickFeature(spec) {
|
||||
if (spec.tags && spec.tags.length > 0) {
|
||||
return spec.tags[0];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 构建转发路由表(供 framework.addRoutes 注册)
|
||||
*/
|
||||
function buildProxyRoutes() {
|
||||
const routes = {};
|
||||
|
||||
for (const [path, methods] of Object.entries(swagger.paths)) {
|
||||
for (const [method, spec] of Object.entries(methods)) {
|
||||
const routeKey = `${method.toUpperCase()} ${path}`;
|
||||
|
||||
routes[routeKey] = async (ctx) => {
|
||||
// 1. 提取 Token
|
||||
const token = extractToken(ctx);
|
||||
if (!token) {
|
||||
ctx.status = 401;
|
||||
ctx.body = { ok: false, error_code: "TOKEN_MISSING", message: "缺少 Token" };
|
||||
return;
|
||||
}
|
||||
|
||||
// 2. 鉴权:Token + 用户 + 订阅 + 套餐功能点 + 接口权限 + 调用量
|
||||
const feature = pickFeature(spec);
|
||||
const authResult = await auth.verifyRequest({ token, feature, api_path: path });
|
||||
if (!authResult.ok) {
|
||||
ctx.status = 403;
|
||||
ctx.body = authResult;
|
||||
return;
|
||||
}
|
||||
|
||||
// 3. 组装 query(去掉 token 参数,避免泄露)
|
||||
const query = { ...ctx.query };
|
||||
delete query.token;
|
||||
|
||||
// 4. 转发到上游
|
||||
const result = await proxy.forwardRequest({
|
||||
api_path: path,
|
||||
method: method.toUpperCase(),
|
||||
query,
|
||||
body: getRequestBody(ctx),
|
||||
headers: ctx.headers || {},
|
||||
auth_ctx: authResult.context,
|
||||
});
|
||||
|
||||
// 5. 原样返回上游响应
|
||||
ctx.status = result.status;
|
||||
ctx.body = result.data;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
return routes;
|
||||
}
|
||||
|
||||
module.exports = { buildProxyRoutes };
|
||||
Reference in New Issue
Block a user