You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Azure APIM入站策略获取X-CSRF-Token为空问题求助

Azure APIM入站策略传递X-CSRF-Token为null问题排查

我正在创建Azure API Management(APIM)入站策略,用于将x-csrf-token传递至POST请求,但在追踪中发现该令牌值为null。使用了适用于SAP Gateway的X-CSRF-Token获取策略片段,目前遇到令牌值为null的问题,求排查解决思路。

相关策略代码如下:

<!--
    IMPORTANT:
    - Policy elements can appear only within the <inbound>, <outbound>, <backend> section elements.
    - To apply a policy to the incoming request (before it is forwarded to the backend service), place a corresponding policy element within the <inbound> section element.
    - To apply a policy to the outgoing response (before it is sent back to the caller), place a corresponding policy element within the <outbound> section element.
    - To add a policy, place the cursor at the desired insertion point and select a policy from the sidebar.
    - To remove a policy, delete the corresponding policy statement from the policy document.
    - Position the <base> element within a section element to inherit all policies from the corresponding section element in the enclosing scope.
    - Remove the <base> element to prevent inheriting policies from the corresponding section element in the enclosing scope.
    - Policies are applied in the order of their appearance, from the top down.
    - Comments within policy elements are not supported and may disappear. Place your comments between policy elements or at a higher level scope.
-->
<!-- The policy defined in this file shows how to implement X-CSRF pattern used by many APIs. The example is specific to SAP Gateway.  -->
<!--    Detailed description of the scenario and solution can be found on: -->
<!--      https://github.com/MartinPankraz/AzureSAPODataReader. -->
<policies>
    <inbound>
        <base />
        <authentication-basic username="{{SAP-test-user}}" password="{{SAP-test-PW}}" />
        <set-variable name="checkRequestUrl" value="@(context.Request.Url.ToString())" />
        <rewrite-uri template="/" />
        <choose>
            <!-- CSRF-token only required for every operation other than GET or HEAD -->
            <when condition="@(context.Request.Method != "GET" && context.Request.Method != "HEAD")">
                <!-- Creating a HEAD subrequest to save request overhead and get the SAP CSRF token and cookie.-->
                <send-request mode="new" response-variable-name="SAPCSRFToken" timeout="10" ignore-error="false">
                    <set-url>@(context.Request.Url.ToString())</set-url>
                    <set-method>HEAD</set-method>
                    <set-header name="X-CSRF-Token" exists-action="override">
                        <value>Fetch</value>
                    </set-header>
                    <set-header name="Authorization" exists-action="override">
                        <value>@(context.Request.Headers.GetValueOrDefault("Authorization"))</value>
                    </set-header>
                </send-request>
                <!-- Extract the token and cookie from the "SAPCSRFToken" and set as header in the POST request. -->
                <choose>
                    <when condition="@(((IResponse)context.Variables["SAPCSRFToken"]).StatusCode == 200)">
                        <set-header name="X-CSRF-Token" exists-action="override">
                            <value>@(((IResponse)context.Variables["SAPCSRFToken"]).Headers.GetValueOrDefault("x-csrf-token"))</value>
                        </set-header>
                        <set-header name="Cookie" exists-action="override">
                            <value>@{
                    string rawcookie = ((IResponse)context.Variables["SAPCSRFToken"]).Headers.GetValueOrDefault("Set-Cookie");
                    string[] cookies = rawcookie.Split(';');
                                /* new session sends a XSRF cookie */
                    string xsrftoken = cookies.FirstOrDefault( ss => ss.Contains("sap-XSRF"));
                                /* existing sessions sends a SessionID. No other cases anticipated at this point. Please create a GitHub Pull-Request if you encounter uncovered settings. */
                                if(xsrftoken == null){
                                    xsrftoken = cookies.FirstOrDefault( ss => ss.Contains("SAP_SESSIONID"));
                                }
                                
                    return xsrftoken.Split(',')[1];}</value>
                        </set-header>
                    </when>
                </choose>
            </when>
        </choose>
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

附追踪截图:
追踪截图1
追踪截图2

排查方向:

  • 检查HEAD请求响应状态:策略仅处理响应状态码为200的情况,若SAP Gateway返回401、403等非200状态,令牌提取逻辑不会执行。需在APIM追踪中查看send-request的实际响应状态码及响应头,确认是否返回了X-CSRF-Token。
  • 修正URL重写影响:策略先执行了<rewrite-uri template="/" />,后续send-request使用的context.Request.Url.ToString()是重写后的URL,可能并非SAP Gateway的有效端点。可将send-request的URL改为之前保存的原始请求URL:@((string)context.Variables["checkRequestUrl"])。
  • 验证Authorization头有效性:策略中send-request的Authorization头取自原始请求,但前面已执行<authentication-basic>,可能原始请求的Authorization头已被覆盖或不存在。可直接使用SAP凭据生成Basic Auth头,或确认context.Request.Headers.GetValueOrDefault("Authorization")能获取有效值。
  • 修复Cookie处理逻辑:策略中用xsrftoken.Split(',')[1]拆分Cookie,若Set-Cookie无逗号会直接报错,导致令牌无法设置。可修改为更稳妥的提取方式:
    var parts = xsrftoken.Split(',');
    return parts.Length > 1 ? parts[1].Trim() : parts[0].Trim();
    
  • 核对头名称大小写:SAP Gateway返回的头可能是X-CSRF-Token而非小写的x-csrf-token,可将提取逻辑改为Headers.GetValueOrDefault("X-CSRF-Token"),确保头名称大小写匹配。

内容的提问来源于stack exchange,提问作者Viknesh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.08 04:20:18