ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Backstage 代理(Proxying)插件实战指南:配置、认证与扩展点全解析

Backstage 代理(Proxying)插件实战指南:配置、认证与扩展点全解析 Backstage 代理Proxying插件实战指南配置、认证与扩展点全解析【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage导读Backstage 后端内置了一个 HTTP 代理插件backstage/plugin-proxy-backend用于让前端插件代码安全地访问后端服务的 API从而规避浏览器跨域CORS限制并将敏感凭据保留在后端。本文以 docs/plugins/proxying.md 为骨架结合仓库内 proxy-backend 与 proxy-node 的源码实现与测试用例完整讲解代理插件的安装、app-config.yaml配置、credentials认证策略、请求/响应头过滤、POST 请求体透传以及通过proxyEndpointsExtensionPoint编程式注册端点的进阶用法。读完本文你将能够在自己的 Backstage 实例中正确配置并安全使用内置代理也能理解其底层行为。注意本文对应的是 Backstage 官方文档中 legacy plugins 文档的一部分但代理的配置与用法同时适用于新旧两套后端系统new backend system 与 legacy backend。如需编写后端插件与模块可参考 Building Backend Plugins and Modules。一、概览代理插件解决了什么问题前端插件通常需要调用第三方服务的 API但直接从前端调用会遇到两个典型问题跨域限制浏览器会阻止跨源请求除非目标服务配置了 CORS。凭据安全把 API Key、Token 等机密放在前端代码里既不安全也不方便管理。Backstage 后端自带的代理插件将这些问题收口在后端前端把请求发往 Backstage 自身的/api/proxy/route路径由代理插件转发到配置的目标服务。凭据可以通过 App Config 插值如${EXAMPLE_AUTH_HEADER}或环境变量注入始终停留服务端。关于何时该用代理、何时该用其他方式与 API 通信的决策分析参见 Call Existing API。代理插件本身依赖社区成熟的http-proxy-middleware包其目标配置格式与该包兼容见 proxy-backend/README.md。二、快速开始安装与启用代理插件默认已经包含在标准 Backstage 工程中packages/app与packages/backend是官方脚手架生成的默认工程。你只需在 backend 入口文件中注册它。新后端New Backend System在packages/backend/src/index.ts中添加backend.add(import(backstage/plugin-proxy-backend));旧后端Legacy Backend旧后端同样在packages/backend/src/index.ts中注册注仓库当前文档原文对两种后端给出的代码示例一致均为上述backend.add(...)写法如果你仍在使用旧的插件注册机制可参照项目脚手架的 legacy 模板相应调整。代理插件核心实现位于 plugins/proxy-backend/src/plugin.ts它通过createBackendPlugin注册proxy插件并依赖rootConfig、discovery、logger、httpRouter等服务在初始化时调用createRouter构建路由。提示仓库中的示例后端还提供了一个什么是我的代理演示路由见 app-config.yaml 的myproxy占位配置方便你快速验证代理是否生效。三、配置app-config.yaml中的proxy根键代理插件的全部配置都位于app-config.yaml的proxy根键下。仓库的示例配置 app-config.yaml 已经预留了该段落并在注释中指引查看 proxy-backend 插件的 README 了解格式。3.1 基本示例# in app-config.yaml proxy: reviveConsumedRequestBodies: true endpoints: /simple-example: http://simple.example.com:8080 /larger-example/v1: target: http://larger.example.com:8080/svc.v1 credentials: require headers: Authorization: ${EXAMPLE_AUTH_HEADER} # ...or interpolating a value into part of a string, # Authorization: Bearer ${EXAMPLE_AUTH_TOKEN}3.2 路由与挂载前缀proxy.endpoints下的每个键都是一个路由匹配项位于代理插件挂载前缀之下若键不以/开头会自动补上前缀/配置 schema 中明确要求以/开头见 config.d.ts。代理插件的标准挂载路径是/api/proxy在 router.ts 中硬编码为pathPrefix /api/proxy。因此上例配置生效后后端请求/api/proxy/simple-example/...与/api/proxy/larger-example/v1/...会被代理接管。3.3 端点的两种值形态每个路由的值可以是简单的 URL 字符串如上例的/simple-example此时等价于以下完整配置target: the string changeOrigin: true pathRewrite: ^url prefixthe string/: / credentials: require符合http-proxy-middleware选项格式的对象并额外支持credentials键可取值见下一节。对象配置直接透传给http-proxy-middleware但有以下三个便捷默认值选项默认行为changeOrigin未指定时设为true最常用的取值会让请求的Host头指向目标地址pathRewrite未指定时自动生成去掉整个前缀与路由的单一重写规则credentials未指定时设为require以上默认逻辑可在 router.ts 的buildMiddleware中看到字符串形态直接{ target: config }对象形态则先剥离credentials再透传。pathRewrite具体效果在上例中自动添加的重写规则为^/api/proxy/larger-example/v1/: /。这意味着请求/api/proxy/larger-example/v1/some/path会被翻译为对http://larger.example.com:8080/svc.v1/some/path的请求——即请求路径中代理前缀与路由部分被剥除剩余路径拼接在 target 之后。3.4 顶层其他设置proxy根键下还有两个全局开关proxy: skipInvalidProxies: true # 遇到无效端点时仅告警而不是启动失败默认 false reviveConsumedRequestBodies: true # 透传被前置中间件消费的请求体默认 false这两个开关在 router.ts 中被读取。其中skipInvalidProxies会让configureMiddlewares在buildMiddleware抛出异常时只记录skipped configuring route due to error告警如 target 不是合法 URL而不是阻断后端启动见 router.ts。四、credentials认证策略详解每个端点对象可选配credentials键控制调用方是否需要携带 Backstage 凭据以及凭据是否转发给目标服务取值含义require调用方必须在每次请求中提供 Backstage 用户或服务凭据凭据不会转发给代理目标。默认值。forward调用方必须提供 Backstage 用户或服务凭据且这些凭据会转发给代理目标。dangerously-allow-unauthenticated访问该代理目标不需要Backstage 凭据。目标服务仍可自行校验凭据但代理不会帮助拦截非 Backstage 认证的调用方。若同时为端点配置allowedHeaders: [Authorization]则调用方提供的 Backstage token如果有会被转发。4.1 全局关闭认证的特殊情况如果在app-config.yaml中设置了backend.auth.dangerouslyDisableDefaultAuthPolicy: true则上述credentials取值不再生效——代理将对所有端点表现得如同配置了dangerously-allow-unauthenticated一样。4.2 源码与测试层面的验证策略校验buildMiddleware会校验credentials取值仅接受require、forward、dangerously-allow-unauthenticated三者否则抛出Unknown credentials policy ...错误见 router.ts。无认证放行当策略为dangerously-allow-unauthenticated时会调用httpRouterService.addAuthPolicy({ path: route, allow: unauthenticated })将对应路由标记为允许匿名访问见 router.ts。凭据转发当策略为forward时authorization头会被加入请求头白名单从而得以转发给目标见 router.ts。以上行为在测试 router.credentials.test.ts 中被逐一验证关键断言包括require以及默认值下无凭据请求返回AuthenticationError: Missing credentials携带Bearer static-token时转发成功但目标侧收到的Authorization为false未转发携带非法 token 时返回Illegal tokenforward下目标侧能收到原样的Authorization头dangerously-allow-unauthenticated下无凭据、静态 token、甚至对 Backstage 非法但对目标合法的 token代理都放行只有同时配置allowedHeaders: [Authorization]时才会转发该头。同文件还验证了路径穿越防护对/api/proxy/test/../../other与/api/proxy/test/%2e%2e/other这类请求代理返回400见 router.credentials.test.ts这对应 router.ts 中对解码后 URL 中..段的拦截逻辑。五、allowedMethods与allowedHeaders限制与脱敏除了credentials端点对象还支持两个安全相关的设置proxy: endpoints: /read-only-api: target: http://readonly.example.com allowedMethods: [GET] # 只放行 GET强制只读 allowedHeaders: [Authorization] # 显式放行 Authorization 头5.1allowedMethods限制被转发的 HTTP 方法。例如allowedMethods: [GET]可强制该代理端点只读。在实现中这是通过自定义中间件过滤器完成的只有req.method命中列表的方法才会被转发见 router.ts。5.2allowedHeaders与默认安全头机制默认情况下代理只转发安全的 HTTP 请求头给目标。这些安全头基于 CORS 认为安全的头集合包括content-type、last-modified等以及所有由代理自身设置的头。完整的默认安全头列表定义在 router.ts包含cache-control, content-language, content-length, content-type, expires, last-modified, pragma, host, accept, accept-language, user-agent如果需要转发其他头例如authorization必须通过allowedHeaders显式开启例如allowedHeaders: [Authorization]。这是为了避免不小心把机密头如cookie、X-Auth-Request-User转发给第三方。相同逻辑同样作用于目标返回给前端的响应头——onProxyRes回调会对响应头做同样的白名单过滤见 router.ts。实现上代理在转发请求前会从req.headers中删除不在白名单内的头在filter中完成而非onProxyReq这是因为启用 global-agent 时onProxyReq触发时机过晚会导致ERR_HTTP_HEADERS_SENT崩溃源码注释中对此有详细说明。六、POST 请求体透传reviveConsumedRequestBodies问题现象当请求体被代理之前的中间件例如 body parser消费后代理转发给目标的请求体会丢失。解决办法在proxy根键下设置proxy: reviveConsumedRequestBodies: true此时会启用http-proxy-middleware的fixRequestBody处理器来修复请求体见 router.ts。注意事项启用后需要确保请求的Content-Type头为application/json或application/x-www-form-urlencoded之一否则fixRequestBody无法正确处理请求体。七、进阶通过proxyEndpointsExtensionPoint编程式注册端点除了配置文件代理插件还支持通过扩展点proxyEndpointsExtensionPoint让代理模块以编程方式注册额外端点。这些端点的载荷格式与 app-config 中的完全相同见前文配置说明。注意app-config 中配置的端点始终会覆盖通过扩展点注册的同名端点——在 router.ts 中最终配置的合并顺序是additionalEndpoints在前、readProxyConfig在后后者来自 app-config会覆盖前者。扩展点接口定义在 plugins/proxy-node/src/alpha/index.tsProxyEndpointsExtensionPoint.addProxyEndpoints(endpoints)接收Recordstring, string | ProxyConfig扩展点的 id 为proxy.endpoints。7.1 脚手架生成模块运行以下命令生成模块骨架yarn new选择backend-module并在提示中填写插件 ID 为proxy。这会生成plugins/proxy-backend-module-moduleId内含src/module.ts与src/index.ts。脚手架生成的包只依赖backstage/backend-plugin-api因此还需要添加提供扩展点的backstage/plugin-proxy-node包yarn --cwd plugins/proxy-backend-module-demo-additional-endpoints add backstage/plugin-proxy-node7.2 模块实现示例用下面的内容替换生成的src/module.tsimport { createBackendModule } from backstage/backend-plugin-api; import { proxyEndpointsExtensionPoint } from backstage/plugin-proxy-node/alpha; export const proxyModuleDemoAdditionalEndpoints createBackendModule({ pluginId: proxy, moduleId: demo-additional-endpoints, register(reg) { reg.registerInit({ deps: { proxyEndpoints: proxyEndpointsExtensionPoint, }, async init({ proxyEndpoints }) { // Replace with however your setup obtains the credential. const largerExampleAuth Bearer token; proxyEndpoints.addProxyEndpoints({ /simple-example: http://simple.example.com:8080, /larger-example/v1: { target: http://larger.example.com:8080/svc.v1, credentials: require, headers: { Authorization: largerExampleAuth, }, }, }); }, }); }, });src/index.ts内容export { proxyModuleDemoAdditionalEndpoints as default } from ./module;7.3 在 backend 入口安装模块在packages/backend/src/index.ts中将模块与代理插件一同注册backend.add(import(backstage/plugin-proxy-backend)); backend.add( import(internal/plugin-proxy-backend-module-demo-additional-endpoints), );模块注册后扩展点回调会把端点并入additionalEndpoints对象见 plugin.ts 的Object.assign逻辑随路由配置一并生效。7.4 配置热更新值得补充的是代理配置支持热更新createRouter会订阅配置变化当proxy.endpoints内容变更时重建路由中间件无需重启后端。这一行为在测试 router.config.test.ts 中被验证——通过MutableConfigSource动态修改配置后新端点立即生效。八、常见问题与安全提醒请求 400如果请求路径包含..段含 URL 编码形式%2e%2e代理会返回400拒绝这是内置的路径穿越防护不要试图绕过。目标 URL 校验target必须是合法字符串 URL否则插件启动时报Proxy target is not a valid URL见 router.ts。凭据泄漏风险默认安全头白名单不会转发cookie、Authorization等敏感头务必不要为了省事而盲目添加allowedHeaders。无认证端点dangerously-allow-unauthenticated意味着任何人只要网络可达都能访问该端点请仅在目标自身有充分防护如白名单、独立认证时使用。全局关闭认证backend.auth.dangerouslyDisableDefaultAuthPolicy: true会让所有端点的credentials配置失效等同于全部匿名放行生产环境务必慎用。如需进一步阅读可查看 plugins/proxy-backend 与 plugins/proxy-node 的源码、config.d.ts 配置 schema以及 router.ts、router.credentials.test.ts 中的实现与测试。【免费下载链接】backstageBackstage is an open framework for building developer portals项目地址: https://gitcode.com/GitHub_Trending/ba/backstage创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表