DotNet YARP 中 ReverseProxy 如何去重请求头里的 Authorization

DotNet YARP 中 ReverseProxy 如何去重请求头里的 Authorization

在使用 YARP 做反向代理时,有时会遇到下游服务收到多个 Authorization 请求头的问题。

典型场景是:

  • 客户端本身已经带了 Authorization
  • 代理层又通过 Transform 额外追加了一次 Authorization
  • 最终下游收到重复的认证头,导致鉴权异常

这篇文章重点说明两个问题:

  1. 为什么会出现重复的 Authorization
  2. YARP ReverseProxy 里应该如何正确处理

为什么会出现重复的 Authorization

YARP 默认会把大多数入站请求头复制到代理请求中。

也就是说,如果客户端请求本身带了:

http 复制代码
Authorization: Bearer user-token

那么这个头默认会被转发到下游。

如果你又在 YARP 配置里额外加了一条类似"设置 Authorization"的规则,就可能形成重复:

  • 原始请求头复制了一份
  • Transform 又新增了一份

结果就是下游看到多个 Authorization

核心思路:不要追加,而是先删后设

如果目标是让下游只收到一个 Authorization,最稳妥的方式是:

  1. 先移除原始 Authorization
  2. 再显式设置你要传给下游的 Authorization

也就是:

  • Remove
  • Set

而不是直接 Append

YARP 配置方式

方案 1:先删除 Authorization,再重新设置

这是最常见、最推荐的做法。

json 复制代码
{
  "ReverseProxy": {
    "Routes": {
      "route1": {
        "ClusterId": "cluster1",
        "Match": {
          "Path": "/api/{**catch-all}"
        },
        "Transforms": [
          { "RequestHeaderRemove": "Authorization" },
          { "RequestHeader": "Authorization", "Set": "Bearer xxx" }
        ]
      }
    },
    "Clusters": {
      "cluster1": {
        "Destinations": {
          "destination1": {
            "Address": "https://backend.example.com/"
          }
        }
      }
    }
  }
}

适用于下面这种情况:

  • 客户端带来的 token 不想直接透传
  • 希望代理层统一改写为内部 token
  • 需要确保下游只收到一个 Authorization

方案 2:如果只是不要转发 Authorization

如果需求不是"替换",而只是"不要把客户端的 Authorization 往下游传",那只删掉即可:

json 复制代码
{
  "ReverseProxy": {
    "Routes": {
      "route1": {
        "ClusterId": "cluster1",
        "Match": {
          "Path": "/api/{**catch-all}"
        },
        "Transforms": [
          { "RequestHeaderRemove": "Authorization" }
        ]
      }
    }
  }
}

这个配置的含义很直接:

  • 客户端可以带 Authorization
  • 但 YARP 转发给下游时会把它移除

方案 3:只转发白名单请求头

还有一种更彻底的方式:不要默认复制所有请求头,而是只允许特定请求头通过。

例如:

json 复制代码
{
  "ReverseProxy": {
    "Routes": {
      "route1": {
        "ClusterId": "cluster1",
        "Match": {
          "Path": "/api/{**catch-all}"
        },
        "Transforms": [
          { "RequestHeadersAllowed": "Content-Type;Accept;X-Request-Id" }
        ]
      }
    }
  }
}

这个配置表示只允许以下请求头被转发:

  • Content-Type
  • Accept
  • X-Request-Id

因为 Authorization 不在白名单里,所以不会被转发。

适用于这些场景:

  • 安全要求较高
  • 不希望客户端头信息污染内部服务
  • 希望代理层完全控制下游收到的头

最容易踩的坑

1. 误用 Append 导致重复

如果使用的是"追加 header"的方式,而不是"覆盖 header"的方式,就容易出现重复。

错误思路:

  • 先保留客户端的 Authorization
  • 再追加一个新的 Authorization

这样下游很可能拿到两个值。

正确思路:

  • 先删
  • 再设

2. 以为 YARP 会自动帮你去重

YARP 的重点是"转发"和"变换",不是自动帮你做业务语义上的去重。

对于 Authorization 这类敏感头,建议显式控制,不要依赖隐式行为。

3. 忘了默认会复制请求头

很多问题的根源其实不是 Transform 本身,而是忽略了这一点:

YARP 默认会复制大多数入站请求头。

所以只要客户端已经带了 Authorization,你后面任何"再设置一次"的操作,都要先思考是否会形成重复。

怎么选方案

情况 1:我要替换 Authorization

json 复制代码
"Transforms": [
  { "RequestHeaderRemove": "Authorization" },
  { "RequestHeader": "Authorization", "Set": "Bearer xxx" }
]

情况 2:我要禁止 Authorization 透传

json 复制代码
"Transforms": [
  { "RequestHeaderRemove": "Authorization" }
]

情况 3:我要严格限制所有可转发请求头

json 复制代码
"Transforms": [
  { "RequestHeadersAllowed": "Content-Type;Accept;X-Request-Id" }
]

结论

DotNet YARP 中,Authorization 请求头重复的根本原因通常是:

  • 默认请求头复制
  • 叠加了额外的请求头设置或追加

正确处理方式不是依赖"自动去重",而是显式控制:

  • 要替换:RequestHeaderRemove + Set
  • 要屏蔽:RequestHeaderRemove
  • 要白名单:RequestHeadersAllowed

一句话总结就是:

在 YARP 里处理 Authorization,最稳妥的做法是先删后设,不要直接追加。

参考文档