使用Azure APIM调用需OAuth2验证的后端API的策略配置求助
Azure APIM 调用OAuth2受保护后端API策略配置方案
原有策略核心问题
- 令牌提取逻辑错误:原有代码拆分Authorization头后取索引0,获取的是
Bearer标识而非实际令牌内容,应取拆分后的索引1内容,同时需补充空值校验避免无认证头的请求抛出异常 - 令牌请求方法错误:OAuth2标准令牌端点仅接受POST请求,原有配置使用GET方法会导致服务端无法识别请求体中的认证参数
- 缺少错误处理逻辑:开启请求忽略错误后未校验令牌接口返回状态,直接读取返回报文中的
access_token字段,令牌请求失败时会触发空引用异常 - 无令牌缓存机制:每次用户请求都重复调用令牌接口,会增加链路耗时,同时容易触发令牌接口的频率限制
修正后完整策略
<policies> <inbound> <base /> <!-- 提取原始请求中的用户令牌,补充空值校验 --> <set-variable name="originBearer" value="@(context.Request.Headers.GetValueOrDefault("Authorization", "").Split(' ').Length >= 2 ? context.Request.Headers.GetValueOrDefault("Authorization", "").Split(' ')[1] : "")" /> <!-- 优先从缓存读取后端接口令牌 --> <cache-lookup-value key="backend-oauth2-token" variable-name="cachedAccessToken" /> <choose> <!-- 缓存无有效令牌时发起令牌请求 --> <when condition="@(!context.Variables.ContainsKey("cachedAccessToken"))"> <send-request ignore-error="false" timeout="20" response-variable-name="bearerTokenResponse" mode="new"> <set-url>{{lookupAccessTokenUrl}}</set-url> <!-- 修正为OAuth2标准要求的POST方法 --> <set-method>POST</set-method> <set-header name="Content-Type" exists-action="override"> <value>application/x-www-form-urlencoded</value> </set-header> <set-body>@{ return $"client_id={{HLR-app-client-id}}&scope={{HLR-scope}}&client_secret={{HLR-secret}}&grant_type=urn:ietf:params:oauth:grant-type:client_credentials&assertion={(string)context.Variables["originBearer"]}&requested_token_use=on_behalf_of"; }</set-body> </send-request> <!-- 校验令牌请求结果 --> <choose> <when condition="@(((IResponse)context.Variables["bearerTokenResponse"]).StatusCode == 200)"> <set-variable name="requestResponseToken" value="@((string)((IResponse)context.Variables["bearerTokenResponse"]).Body.As<JObject>()["access_token"])" /> <!-- 令牌写入缓存,缓存时长设置为比令牌有效期短1分钟,避免使用过期令牌 --> <cache-store-value key="backend-oauth2-token" value="@((string)context.Variables["requestResponseToken"])" duration="3540" /> </when> <otherwise> <!-- 令牌获取失败直接返回错误信息 --> <return-response> <set-status code="500" reason="Backend token acquisition failed" /> <set-body>@(((IResponse)context.Variables["bearerTokenResponse"]).Body.As<string>())</set-body> </return-response> </otherwise> </choose> </when> <otherwise> <!-- 缓存存在令牌直接复用 --> <set-variable name="requestResponseToken" value="@((string)context.Variables["cachedAccessToken"])" /> </otherwise> </choose> <!-- 替换请求头为后端所需的认证令牌 --> <set-header name="Authorization" exists-action="override"> <value>@($"Bearer {(string)context.Variables["requestResponseToken"]}")</value> </set-header> </inbound> <backend> <base /> </backend> <outbound> <base /> </outbound> <on-error> <base /> </on-error> </policies>
配置注意事项
- 如果你使用的是纯客户端凭证流而非On-Behalf-Of流,直接删除请求体中的
assertion和requested_token_use参数即可 - 缓存时长
duration可根据你的令牌实际有效期调整,需保证比令牌有效期短至少30秒 - 所有
{{}}包裹的命名值需提前在APIM的「命名值」模块配置完成,敏感参数(如client_secret)建议设置为密钥类型加密存储 - 确认你的APIM实例已开启内置缓存,若使用的是消费层级APIM,缓存功能不可用时可删除缓存相关策略,每次请求实时获取令牌即可
内容的提问来源于stack exchange,提问作者Lise
相关产品推荐
相关产品推荐

