【Azure API 管理】APIM如何實現對部分固定IP進行訪問次數限制呢?如60秒10次請求

路邊兩盞燈發表於2023-04-24

問題描述

使用Azure API Management, 想對一些固定的IP地址進行訪問次數的限制,如被限制的IP地址一分鐘可以訪問10次,而不被限制的IP地址則可以無限訪問?

【Azure API 管理】APIM如何實現對部分固定IP進行訪問次數限制呢?如60秒10次請求

 

ChatGPT 解答

最近ChatGPT爆火,所以也把這個問題讓ChatGPT來解答,然後人工驗證它的回答正確與否?

【Azure API 管理】APIM如何實現對部分固定IP進行訪問次數限制呢?如60秒10次請求

根據對APIM Policy的文件參考, choose 和 rate-limit 策略組合理論上的確可以實現要求, 接下來就讓我們實際驗證:

 

驗證步驟

1)在API的Inbound 策略中新增 choose策略

【Azure API 管理】APIM如何實現對部分固定IP進行訪問次數限制呢?如60秒10次請求

(策略具體內容,見文末)

2) 測試驗證,連續對該API訪問10次以上,得到429 Too Many Requests錯誤

【Azure API 管理】APIM如何實現對部分固定IP進行訪問次數限制呢?如60秒10次請求

3)以上證明,ChatGPT針對這個問題的解答是正確的!

 

工程師解答

在參考ChatGPT給出的 choose + rate limit 組合後,我們也發現另一個選項。使用 rate-limit-by-key 策略實現對特定IP的速率限制。

  • rate-limit-by-key 策略https://docs.azure.cn/zh-cn/api-management/api-management-access-restriction-policies#LimitCallRateByKey , 可以對呼叫速率進行限制,使指定時段的呼叫不超出指定的數目,避免單個金鑰的 API 使用量暴增。 金鑰的值可以是任意字串,通常使用策略表示式來提供金鑰。 可以新增可選增量條件,指定在決定是否到達限制值時應該進行計數的請求。 超過此呼叫速率時,呼叫方會收到 429 Too Many Requests 響應狀態程式碼。

在官方文件中給出的示例中,是針對所有的IP(context.Request.IpAddress)都進行了10次/60秒請求的限制,而本示例中則特指“某些固定IP”限制。那麼如何來完成這個需求呢?

【Azure API 管理】APIM如何實現對部分固定IP進行訪問次數限制呢?如60秒10次請求

答案 就在“rate-limit-by-key 策略”的說明中,”可以新增可選增量條件,指定在決定是否到達限制值時應該進行計數的請求”, 所以,只要可選增量條件(increment-condition) 的值根據輸入的IP地址動態賦值True/False, 就能完美匹配以上要求。

【Azure API 管理】APIM如何實現對部分固定IP進行訪問次數限制呢?如60秒10次請求

 

理論推斷,只需要實現如下邏輯,即可以實現終極需求“想對一些固定的IP地址進行訪問次數的限制,如被限制的IP地址一分鐘可以訪問10次,而不被限制的IP地址則可以無限訪問?

只需兩步:

1)透過設定一個變數(set-variable) 值,用C#程式碼來計算變數值,在賦值語句中,預先定義一個IP限制列表,透過 contains 檢查當前請求IP是否在列表中,返回True or False 。True表示當前請求的IP需要速率限制, 否則,不需要。

2) 然後,在rate-limit-by-key 的 increment-condition條件中使用上一步引數值,進行判斷是否計入限制

驗證步驟

1)在API的 Inbound 策略中新增 rate-limit-by-key策略

【Azure API 管理】APIM如何實現對部分固定IP進行訪問次數限制呢?如60秒10次請求

(策略具體內容,見文末)

 

2)驗證在30秒,訪問5次以上後,同樣得到429 Too Many Requests錯誤

 【Azure API 管理】APIM如何實現對部分固定IP進行訪問次數限制呢?如60秒10次請求

3) 當在請求Headers中新增Ocp-Apim-Trace: true 和 Ocp-Apim-Subscription-Key: {訂閱Key}後,可以檢視請求在APIM中執行的日誌跟蹤。可以檢視rate-limit-by-key 策略的執行情況.

【Azure API 管理】APIM如何實現對部分固定IP進行訪問次數限制呢?如60秒10次請求

 

總結

想實現固定IP地址訪問次數的限制,至少有如下兩種解決方案。

方案一:Choose + rate-limit 策略組合

<!--
    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.
-->
<policies>
    <inbound>
        <base />
        <set-variable name="IsCountIpLimit" value="@{
                string ipAddress =context.Request.IpAddress; 

                List<string> cidrList = new List<string>(){
                    "167.xxx. xxx.135",
                    "167.xxx. xxx.136",
                    "167.xxx. xxx.137"
                };
                return cidrList.Contains(ipAddress);
                }" />
        <choose>
            <when condition="@((bool)context.Variables["IsCountIpLimit"])">
                <rate-limit calls="10" renewal-period="60" />
            </when>
        </choose>
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

 

方案二:rate-limit-by-key策略

<!--
    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.
-->
<policies>
    <inbound>
        <base />
        <set-variable name="IsCountIpLimit" value="@{
                string ipAddress =context.Request.IpAddress; 

                List<string> limitIPs = new List<string>(){
                    "167.xxx. xxx.135",
                    "167.xxx. xxx.136",
                    "167.xxx. xxx.137"
                };

                return limitIPs.Contains(ipAddress);
                }" />
        <rate-limit-by-key calls="5" renewal-period="30" counter-key="@(context.Request.IpAddress)" increment-condition="@(context.Response.StatusCode >= 200 && context.Response.StatusCode < 300 && (bool)context.Variables["IsCountIpLimit"])" />
    </inbound>
    <backend>
        <base />
    </backend>
    <outbound>
        <base />
    </outbound>
    <on-error>
        <base />
    </on-error>
</policies>

 

 

參考資料

choose策略https://docs.azure.cn/zh-cn/api-management/api-management-advanced-policies#choose 

rate-limit策略https://docs.azure.cn/zh-cn/api-management/api-management-access-restriction-policies#LimitCallRate ,

rate-limit-by-key 策略https://docs.azure.cn/zh-cn/api-management/api-management-access-restriction-policies#LimitCallRateByKey 

 

相關文章