レートリミットってご存知ですか?
いろいろ言い方はあるかもしれませんが、
「指定期間内に実行できるリクエスト数の制限」
という風に捉えています。
今回、webサービスにてレートリミットを実装したのでメモ。尚要件として、
・ログインしていない場合はCookieベース
・ログインしていたらログインIDベース
で端末を識別するようにしています。
本来ここに「ログイン試行回数は5分間に5回まで(ログインしたらリセット)」や、「パスワード再発行リクエストは1時間に5回まで」みたいな個別のパターンも必要でしょうが、ここでは省きます。
実際のコード
まず、.NET7以上が前提の書き方です。7以上の場合、純正の仕組みが使えます。
Program.csを開き、usingを追加。
using System.Threading.RateLimiting;もうそのままの名前ですね。
そしてProgram.csにて、builderへの記述と呼び出しの二箇所を追加。
...
builder.Services.AddRateLimiter(options =>
{
  options.AddPolicy("ratelimit-policy", httpContext =>
    {
        ...ログイン済みか判定するためにユーザ情報を取得する処理を記述。(プロジェクト依存)
        var userId = ---;
        if (!string.IsNullOrEmpty(userId))
        {
            return RateLimitPartition.GetFixedWindowLimiter(userId, key =>
                new FixedWindowRateLimiterOptions
                {
                    PermitLimit = 100,
                    Window = TimeSpan.FromMinutes(1) //直近1分間で100回までOKの意
                }            
            );
        }
        else
        {
            // 未認証の場合、クッキーを使って検証する
            var cookieId = httpContext.Request.Cookies["deviceId"];
            if (string.IsNullOrEmpty(cookieId))
            {
                // クッキーが存在しない場合、新しいIDを生成してクッキーにセット
                cookieId = Guid.NewGuid().ToString();
                httpContext.Response.Cookies.Append("deviceId", cookieId);
            }
            return RateLimitPartition.GetFixedWindowLimiter(cookieId, key =>
                new FixedWindowRateLimiterOptions
                {
                    PermitLimit = 100,
                    Window = TimeSpan.FromMinutes(1)
                }            
            );
        }
    });
    // ブロック時のステータスコード
    options.RejectionStatusCode = 429;
});
--Buildする前に記述。
var app = builder.Build();
...
app.UseAuthorization();
--認証ポリシーの後に記述
app.UseRateLimiter(); 
...
そしてコントローラにてポリシーを適用します。
[EnableRateLimiting("ratelimit-policy")]
public class HogeController : ControllerBase
...
試しにリミット値を厳しめにして、対象URLにブラウザリロードやSwaggerでアクセスしてみてください。
まとめ
公式が対応してくれただけあって簡単ですね。ただこれだけでは足りないところもありますので、自身の開発するサービスと照らし合わせて、どこに個別対応が必要か考えてください。

