AspNetCoreRateLimit 學習


GitHub:https://github.com/stefanprodan/AspNetCoreRateLimit

Coding:https://huawu.coding.net/public/aspnetcoreratelimit/aspnetcoreratelimit/git/files

 

主要包含 IP 和 ClientID 兩種規則

IP

優先獲取請求頭:X-Real-IP

其次獲取:_httpContextAccessor.HttpContext.Connection.RemoteIpAddress?.ToString()

 

ClientID 

使用配置中 ClientIdHeader 定義的請求頭 

如:ClientIdHeader:X-ClientId,則請求頭為:X-ClientId

 

普通規則 GeneralRules 用法

1.當啟用 EnableEndpointRateLimiting 時,會匹配 普通規則中 * 或 *:/matching_path 或 matching_verb:/matching_path  會對比一個 IsUrlMatch 方法

var limits = new List<RateLimitRule>();

//rules 為對應的IP或ClientID中定義的Rules if (rules?.Any() == true) { if (_options.EnableEndpointRateLimiting) { // search for rules with endpoints like "*" and "*:/matching_path" string path = _options.EnableRegexRuleMatching ? $".+:{identity.Path}" : $"*:{identity.Path}"; var pathLimits = rules.Where(r => path.IsUrlMatch(r.Endpoint, _options.EnableRegexRuleMatching)); limits.AddRange(pathLimits); // search for rules with endpoints like "matching_verb:/matching_path" var verbLimits = rules.Where(r => $"{identity.HttpVerb}:{identity.Path}".IsUrlMatch(r.Endpoint, _options.EnableRegexRuleMatching)); limits.AddRange(verbLimits); } else { // ignore endpoint rules and search for global rules only var genericLimits = rules.Where(r => r.Endpoint == "*"); limits.AddRange(genericLimits); } // get the most restrictive limit for each period limits = limits.GroupBy(l => l.Period).Select(l => l.OrderBy(x => x.Limit)).Select(l => l.First()).ToList(); }

2.否則 精確匹配 普通規則中 EndPoint 等於 * 

 

IP和ClientID中的Rules

所有的通用規則和自定義規則都會生效,精確匹配的Endpoint 最好設置的規則比 *規則范圍小
如果有和通用規則 Period 相等的規則,則優先使用此處的

 

public static bool IsUrlMatch(this string source, string value, bool useRegex)
{
    if (useRegex)
    {
        return IsRegexMatch(source, value);
    }
    return source.IsWildCardMatch(value);
}

public static bool IsWildCardMatch(this string source, string value)
{
    return source != null && value != null && source.ToLowerInvariant().IsMatch(value.ToLowerInvariant());
}

public static bool IsMatch(this string value, string pattern, char singleWildcard = '?', char multipleWildcard = '*')
{

    int[] inputPosStack = new int[(value.Length + 1) * (pattern.Length + 1)];   // Stack containing input positions that should be tested for further matching
    int[] patternPosStack = new int[inputPosStack.Length];                      // Stack containing pattern positions that should be tested for further matching
    int stackPos = -1;                                                          // Points to last occupied entry in stack; -1 indicates that stack is empty
    bool[,] pointTested = new bool[value.Length + 1, pattern.Length + 1];       // Each true value indicates that input position vs. pattern position has been tested

    int inputPos = 0;   // Position in input matched up to the first multiple wildcard in pattern
    int patternPos = 0; // Position in pattern matched up to the first multiple wildcard in pattern

    //if (pattern == null)
    //    pattern = string.Empty;

    // Match beginning of the string until first multiple wildcard in pattern
    while (inputPos < value.Length && patternPos < pattern.Length && pattern[patternPos] != multipleWildcard && (value[inputPos] == pattern[patternPos] || pattern[patternPos] == singleWildcard))
    {
        inputPos++;
        patternPos++;
    }

    // Push this position to stack if it points to end of pattern or to a general wildcard character
    if (patternPos == pattern.Length || pattern[patternPos] == multipleWildcard)
    {
        pointTested[inputPos, patternPos] = true;
        inputPosStack[++stackPos] = inputPos;
        patternPosStack[stackPos] = patternPos;
    }

    bool matched = false;

    // Repeat matching until either string is matched against the pattern or no more parts remain on stack to test
    while (stackPos >= 0 && !matched)
    {
        inputPos = inputPosStack[stackPos];         // Pop input and pattern positions from stack
        patternPos = patternPosStack[stackPos--];   // Matching will succeed if rest of the input string matches rest of the pattern

        if (inputPos == value.Length && patternPos == pattern.Length)
            matched = true;     // Reached end of both pattern and input string, hence matching is successful
        else if (patternPos == pattern.Length - 1)
            matched = true;     // Current pattern character is multiple wildcard and it will match all the remaining characters in the input string
        else
        {
            // First character in next pattern block is guaranteed to be multiple wildcard
            // So skip it and search for all matches in value string until next multiple wildcard character is reached in pattern

            for (int curInputStart = inputPos; curInputStart < value.Length; curInputStart++)
            {

                int curInputPos = curInputStart;
                int curPatternPos = patternPos + 1;

                while (curInputPos < value.Length && curPatternPos < pattern.Length && pattern[curPatternPos] != multipleWildcard &&
                       (value[curInputPos] == pattern[curPatternPos] || pattern[curPatternPos] == singleWildcard))
                {
                    curInputPos++;
                    curPatternPos++;
                }

                // If we have reached next multiple wildcard character in pattern without breaking the matching sequence, then we have another candidate for full match
                // This candidate should be pushed to stack for further processing
                // At the same time, pair (input position, pattern position) will be marked as tested, so that it will not be pushed to stack later again
                if (((curPatternPos == pattern.Length && curInputPos == value.Length) || (curPatternPos < pattern.Length && pattern[curPatternPos] == multipleWildcard))
                    && !pointTested[curInputPos, curPatternPos])
                {
                    pointTested[curInputPos, curPatternPos] = true;
                    inputPosStack[++stackPos] = curInputPos;
                    patternPosStack[stackPos] = curPatternPos;
                }
            }
        }
    }

    return matched;
}

 

動態修改規則

在Main 方法中添加如下代碼

        var host=hostBuilder.Build()

            #region RateLimit 很關鍵,動態修改規則
            using (var scope = host.Services.CreateScope())
            {
                // get the ClientPolicyStore instance
                var clientPolicyStore = scope.ServiceProvider.GetRequiredService<IClientPolicyStore>();
                // seed Client data from appsettings
                _ = clientPolicyStore.SeedAsync();

                // get the IpPolicyStore instance
                var ipPolicyStore = scope.ServiceProvider.GetRequiredService<IIpPolicyStore>();
                // seed IP data from appsettings
                _ = ipPolicyStore.SeedAsync();
            }
            #endregion

            host.Run();    

  

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM