使用应用程序网关时对请求 IP 地址进行筛选Filter on request IP Address when using an Application Gateway

本文展示了一个 Azure API 管理策略示例,该示例演示了当通过应用程序网关或其他中介访问 API 管理实例时,如何筛选请求 IP 地址。This article shows an Azure API management policy sample that demonstrates how filter on the request IP address when the API Management instance is accessed through an Application Gateway or other intermediary. 若要设置或编辑策略代码,请执行设置或编辑策略中所述的步骤。To set or edit a policy code, follow the steps described in Set or edit a policy. 若要查看其他示例,请参阅策略示例To see other examples, see policy samples.

策略Policy

将代码粘贴到“入站”块中 。Paste the code into the inbound block.

<!-- 
    The policy defined in this file shows how to filter request IPs when the API Management instance 
    is accessed from an Application Gateway.  The Application Gateway will write the original request
    IP to the "X-Forwarded-For" header.  The set-header policy evaluates this IP address against a list of
    IP ranges (if any).  If a match is found, a value is written to the X-Forwarded-For header and the
    following check-header policy will validate the match.  If no match is found 
-->
<policies>
    <inbound>
        <base />
        <!-- Save the X-Forwarded-For value -->
        <set-variable name="originalXForwardedForValue" value="@(context.Request.Headers.GetValueOrDefault("X-Forwarded-For"))" />
        <!-- Check the client IP value in the X-Forwarded-For header-->
        <set-header name="X-Forwarded-For" exists-action="override">
            <value>@{
            int HostToNetworkOrder(int host)
            {
                return (((int)HostToNetworkOrderShort((short)host) & 0xFFFF) << 16)
                    | ((int)HostToNetworkOrderShort((short)(host >> 16)) & 0xFFFF);
            }
            short HostToNetworkOrderShort(short host)
            {
                return (short)((((int)host & 0xFF) << 8) | (int)((host >> 8) & 0xFF));
            }
            
            string ipAddress = context.Request.Headers.GetValueOrDefault("x-forwarded-for",""); 
            if (!string.IsNullOrEmpty(ipAddress))
            {
                string[] tokens = ipAddress.Split(':'); 
                if(tokens.Length == 2) 
                { ipAddress = tokens[0]; } 
                //Place IP Ranges into this list in CIDR notation (e.g. "0.0.0.0/0") and separate with commas
                List<string> cidrList = new List<string>(){
                    "10.0.0.0/8",
                    "172.0.0.0/24",
                    "192.168.0.0/24"
                };
                foreach (string cidrAddress in cidrList)
                {
                    string[] cidrParts = cidrAddress.Split('/');
                    string[] inputIPParts = ipAddress.Split('.');
                    string[] cidrIPArray = cidrParts[0].Split('.');

                    if (inputIPParts.Length == 4 && cidrIPArray.Length == 4)
                    {
                        byte[] inputIPBytes = new byte[] {Convert.ToByte(int.Parse(inputIPParts[0])), 
                            Convert.ToByte(int.Parse(inputIPParts[1])), 
                            Convert.ToByte(int.Parse(inputIPParts[2])),
                            Convert.ToByte(int.Parse(inputIPParts[3])), };
                        byte[] cidrIPBytes = new byte[] {Convert.ToByte(int.Parse(cidrIPArray[0])), 
                            Convert.ToByte(int.Parse(cidrIPArray[1])), 
                            Convert.ToByte(int.Parse(cidrIPArray[2])),
                            Convert.ToByte(int.Parse(cidrIPArray[3])), };
                
                        int cidrAddr = BitConverter.ToInt32(inputIPBytes,0);
                        int ipAddr = BitConverter.ToInt32(cidrIPBytes,0);
                        
                        var host = int.Parse(cidrParts[1]);
                        host = -1 << (32-host);
                        var mask = HostToNetworkOrder(host);
                        
                        if (((ipAddr & mask) == (cidrAddr & mask)))
                        {
                            return "{{ipValidated}}";
                        }
                    }
                }
            }
            return ipAddress; }</value>
        </set-header>
        <check-header name="x-forwarded-for" failed-check-httpcode="403" failed-check-error-message="Unauthorized" ignore-case="true">
            <value>10.33.215.173</value>
            <value>10.33.215.175</value>
            <value>{{ipValidated}}</value>
        </check-header>
        <!-- Revert X-Forwarded-For to its original value-->
        <set-header name="X-Forwarded-For" exists-action="override">
            <value>@{
                return context.Variables.GetValueOrDefault<string>("originalXForwardedForValue");
                }
            </value>
        </set-header>
    </inbound>
</policies>

后续步骤Next steps

了解有关 APIM 策略的详细信息:Learn more about APIM policies: