ASP.NET

ASP.NET Web API のセキュリティ フィルター

Badrinarayanan Lakshmiraghavan

認証と承認は、アプリケーション セキュリティの土台です。認証とは、指定された資格情報を検証することでユーザーの ID を確立することです。承認とは、ユーザーが要求した操作の実行を許可するかどうかを決定することです。セキュアな Web API は、要求を認証し、確立された ID を基に要求されたリソースへのアクセスを承認します。

ASP.NET Web API に認証を実装する場合、ASP.NET Web API パイプラインの中で利用可能な拡張ポイントを使用するか、ホストによって提供されるオプションを使用します。ASP.NET Web API の最初のバージョンでの一般的な認証実装方法は、承認フィルターまたはアクション フィルターを使用する方法です。ASP.NET Web API 2 では、この認証実装プロセスに専用の認証フィルターが新しく導入されます。この新しい拡張ポイントにより、認証と承認それぞれの懸念事項を明確に分離できまるようになります。今回は、承認フィルターと認証フィルターという 2 つのセキュリティ フィルターを紹介し、これらのフィルターを使用して認証と承認を個別の処理として ASP.NET Web API に実装する方法を示します。

セキュリティの実装に関するオプション

ASP.NET Web API での認証と承認は、ホストが提供する拡張ポイントと ASP.NET Web API パイプライン自体で利用可能な拡張ポイントを使用して実装できます。ホストベースのオプションには、HTTP モジュールや OWIN ミドルウェアのコンポーネントなどがあります。これに対して、ASP.NET Web API の拡張オプションは、メッセージ ハンドラー、アクション フィルター、承認フィルター、および認証フィルターから構成されます。

ホストベースのオプションは、ホスト パイプラインに適切に統合され、無効な要求をパイプラインの初期段階で拒否できます。一方、ASP.NET Web API の拡張オプションは、認証プロセスを細部のレベルまで制御できるようにします。つまり、さまざまなコントローラーに異なる認証メカニズムを設定できるだけでなく、さまざまなアクション メソッドにも異なる認証メカニズムを設定できます。どちらのオプションを使用するかは、ホストと適切に統合して無効な要求を初期段階で拒否するか、認証を細部まで制御するかによって決まります。このような全般的な特徴のほか、各オプションにもそれぞれ独自の長所と短所があります。これについては、この後説明します。

HTTP モジュール: IIS で実行される Web API のオプションです。HTTP モジュールにより、IIS パイプラインの一環としてセキュリティ コードを初期段階に実行できるようになります。HTTP モジュールで確立されたプリンシパルは、パイプラインの後半で実行される IIS コンポーネントを含め、すべてのコンポーネントで使用できます。たとえば、AuthenticateRequest イベントによって起動される HTTP モジュールによってプリンシパルが確立されると、そのプリンシパルのユーザー名は、IIS ログの cs-username フィールドに正しく記録されます。HTTP モジュールの最大の欠点は、粒度に欠けることです。HTTP モジュールは、アプリケーションが受信するすべての要求に対して実行されます。HTML マークアップ生成や Web API など、さまざまな機能を持つ Web アプリケーションの場合、HTTP モジュールによる一方向の認証の適用は、一般的に十分な柔軟性がある方法ではありません。HTTP モジュールを使用する場合のもう 1 つの欠点は、ホスト (この場合は IIS) との依存関係です。

OWIN ミドルウェア: OWIN ホストと共に利用可能なホスト関連のオプションです。ASP.NET Web API 2 では、OWIN が完全にサポートされます。セキュリティに OWIN ミドルウェアを使用する最も説得力のある理由は、おそらく、同じミドルウェアがさまざまなフレームワークで機能することです。つまり、アプリケーションでは ASP.NET Web API や SignalR など、複数のフレームワークを使用することができますが、同時に共通のセキュリティ ミドルウェアも使用できることになります。ただし、OWIN ミドルウェアの場合も粒度に欠けることが問題になります。OWIN ミドルウェアも OWIN パイプラインで実行され、通常はすべての要求に対して呼び出されるためです。OWIN ミドルウェアは、OWIN 互換のホストでのみ使用できますが、この依存関係は、HTTP モジュールのような特定のホストやサーバー (IIS など) との依存関係に比べれば緩やかなものといえます。注目すべき点は、Microsoft.Owin.Host.SystemWeb パッケージのおかげで、OWIN ミドルウェアを (IIS 統合) ASP.NET パイプラインで実行できるようになったことです。

メッセージ ハンドラー: ASP.NET Web API によって提供される拡張オプションです。セキュリティにメッセージ ハンドラーを使用する最大のメリットは、メッセージ ハンドラーが ASP.NET Web API フレームワークに含まれる概念なので、基になるホストやサーバーに依存しないことです。また、メッセージ ハンドラーは、Web API 要求に対してのみ実行されます。メッセージ ハンドラーを使用するデメリットは、細部まで制御できない点です。メッセージ ハンドラーは、すべての要求または特定ルートのグローバル ハンドラーとして実行されるように構成します。特定ルートには、複数のコントローラーを含めることができます。そのため、これらすべてのコントローラーと、各コントローラーに含まれるアクション メソッドは、そのルート用に構成されたメッセージ ハンドラーで適用される同じ認証を共有しなければなりません。つまり、メッセージ ハンドラーをルート レベルに設定すると、メッセージ ハンドラーで実装される認証は、最も粒度に欠けることになります。

アクション フィルター: ASP.NET Web API によって提供される拡張オプションです。ただし、認証の実装という点では現実的なオプションではありません。それは、単純に ASP.NET Web API パイプラインで承認フィルターが実行された後にアクション フィルターが実行されるためです。認証と承認を正しく動作させるには、承認の前に認証を行わなければなりません。

承認フィルター: ASP.NET Web API によって提供される拡張オプションです。メッセージ ハンドラーよりも細部まで制御できることを求められるシナリオでカスタム認証を実装する最も一般的な方法の 1 つが承認フィルターの使用です。認証と承認の両方に承認フィルターを使用する大きな問題は、承認フィルターの実行順序が ASP.NET Web API によって保証されない点にあります。基本的には、承認を実行する承認フィルターは、認証を実行する承認フィルターよりも前に実行された場合に適切に機能するため、このオプションも、アクション フィルター オプションと同様、認証には適切ではありません。

認証フィルター: 今回のテーマです。これは、ASP.NET Web API 2 で利用可能になった最新拡張オプションです。認証フィルターは、メッセージ ハンドラーの後、他のすべての種類のフィルターよりも前に実行されます。そのため、認証の懸案事項の実装に適切な選択肢になります。最も重要な点は、承認フィルターよりも前に実行されることです。認証と承認のいずれかを明確に対象とするフィルターを使用することにより、認証と承認それぞれの懸念事項を分離できます。

さらに、認証フィルターには、特にフィルターの効果を上げる制御や粒度のレベルが用意されています。ネイティブ モバイル アプリケーションとブラウザーベースの AJAX アプリケーションの両方から使用されるように設計された Web API の場合を考えてみます。モバイル アプリケーションの場合は HTTP Authorization ヘッダーでトークンを提示します。一方、AJAX アプリケーションは資格情報として認証 Cookie を使用します。また、API のサブセットは機密度が高く、ネイティブ モバイル アプリケーションのみに使用できるものとし、Cookie ではなくトークンを提示した場合にのみアクション メソッドにアクセスできるものとします。これは、Cookie がクロスサイト リクエスト フォージェリ (XSRF) の影響を受けやすいのに対し、HTTP Authorization ヘッダー内のトークンはその影響を受けないためです。この場合、ホストベースのオプションやメッセージ ヘッダーで実現できない細かい粒度で認証を行う必要があります。このような場合に最も適しているのが認証フィルターです。つまり、トークンに基づく認証フィルターを使用する必要があるすべてのコントローラーやアクション メソッドには、この認証フィルターを適用し、それ以外のコントローラーやアクション メソッドには Cookie に基づく認証フィルターを適用できます。このシナリオでは、いくつかの一般的なアクション メソッドがあり、それらのメソッドにトークンまたは Cookie のいずれかを提示してアクセスできるようにするものとします。Cookie とトークン両方の認証フィルターをこれらの一般的なアクション メソッドに適用するだけで、いずれかのフィルターが適切な認証を実行します。この種の制御は、認証フィルターがもたらす最も大きな価値です。認証を細かく制御する必要がある場合に適切な方法は、認証の懸念事項を認証フィルターで、承認の懸念事項を承認フィルターで対処することです。

ここで重要な点に触れておきます。ASP Web API 2 付属の認証フィルター HostAuthenticationFilter を使用すると、OWIN ミドルウェアによる ASP.NET Web API 認証を実行できます。OWIN 認証ミドルウェアはパイプライン内で実行され、着信要求を "アクティブに" 認証しようと試みますが、必要に応じて要求を "パッシブに" 認証するよう構成することも可能です。HostAuthenticationFilter により、パッシブな OWIN 認証ミドルウェアを Web API パイプラインの後半に名前を指定して実行できるようになります。この方法では、フレームワーク (マイクロソフトが提供する OWIN 認証ミドルウェアを含む) 間で認証コードを共有できるようになると同時に、アクション単位に細かく認証を行うこともできるようになります。

ホストレベルの認証と、細かい制御が可能な Web API パイプライン ベースの認証を混在させることもできますが、その場合、ホストレベルの認証が Web API の認証にどのように影響するかを慎重に検討する必要があります。たとえば、他のフレームワーク (ASP.NET MVC など) と併用できるように、ホストレベルで Cookie ベースの認証ミドルウェアを用意してもかまいませんが、Web API に Cookie ベースのプリンシパルを使用させると、XSRF などの攻撃を受けやすくなります。このような状況では、SuppressDefaultHostAuthentication 拡張メソッドを使用することによって、Web API がホストレベルで構成された認証を無視できるようになります。既定の Web API Visual Studio テンプレートは、ホストレベルでは Cookie が有効になっており、Web API レベルでは署名なしトークンを使用します。Cookie がホストレベルで有効になっていて、XSRF を緩和する必要があるため、テンプレートでは、Web API パイプラインが Cookie ベースのプリンシパルを使用しないように SuppressDefaultHostAuthentication も使用します。こうすれば、Web API はトークンベースのプリンシパルしか使用しないため、XSRF 攻撃を防ぐメカニズムを Web API 用に作成する必要はなくなります。

認証フィルターと承認フィルターの連携

ASP.NET Web API パイプラインでは、認証フィルターがまず実行され、次に承認フィルターが実行されます。これは、認証の結果として確立された ID を承認が利用するという単純な理由によるものです。ここでは、ASP.NET Web API のセキュリティを確保するために認証フィルターと承認フィルターが連携するように設計する方法を示します。

この設計の基本的な考え方として、認証フィルターには、資格情報を検証する役割だけを持たせ、その他の事項には対処しません。たとえば、認証フィルターは、資格情報が提示されない場合に "401 権限がありません" という状態コードを示して要求を拒否することはしません。この場合はシンプルに認証済みの ID を確立しないで、匿名要求の処理方法に関する問題を未解決ままにして承認段階に残します。

  1. 要求で必要な資格情報が提示されなかったら、何もしない。
  2. 資格情報が提示され、有効であることが分かったら、認証済みプリンシパルの形式で ID を確立する。
  3. 資格情報が提示されても無効であると分かった場合、エラーの結果を設定して ASP.NET Web API フレームワークに通知し、"権限がありません" という応答を要求元に返す。

パイプライン内で実行されている認証フィルターが無効な資格情報を検出できない場合、認証済み ID が確立されていない状態でも、パイプラインは動作を続けます。このような匿名要求の処理方法を決定するのは、パイプラインの後半で実行されるコンポーネントです。

最も基本的なレベルでは、承認フィルターは、確立する ID が認証済み ID かどうかをチェックするだけです。ただし、承認フィルターは次のことも確認できます。

  • 認証済みの ID のユーザー名が、許可済みユーザーの一覧に記載されていること。
  • 認証済み ID に関連付けられた役割の 1 つ以上が、許可済み役割の一覧に記載されていること。

既定の承認フィルターは、前述のように役割ベースのアクセス制御のみを実行しますが、既定の承認フィルターから派生するカスタム承認フィルターでは、認証フィルターによって確立された ID に含まれる要求を確認することで、要求ベースのアクセス制御を実行することができます。

すべての承認フィルターが正しく処理されると、パイプラインは動作を続け、最終的には、API コントローラーのアクション メソッドによって、要求に対する応答が生成されます。ID が確立されない場合またはユーザー名や役割の要件に不一致がある場合、承認フィルターは "401 権限がありません" 応答を返して要求を拒否します。図 1 は、3 つのシナリオ (資格情報が提示されない場合、無効な資格情報が提示された場合、有効な資格情報が提示された場合) における 2 つのフィルターが行う処理を示しています。

ASP.NET Web API パイプラインのセキュリティ フィルター
図 1 ASP.NET Web API パイプラインのセキュリティ フィルター

認証フィルターの作成

認証フィルターとは、IAuthenticationFilter インターフェイスを実装するクラスです。このインターフェイスには、次に示すように、AuthenticateAsync と ChallengeAsync という 2 つのメソッドがあります。

public interface IAuthenticationFilter : IFilter
{
  Task AuthenticateAsync(HttpAuthenticationContext context, 
    CancellationToken cancellationToken);
  Task ChallengeAsync(HttpAuthenticationChallengeContext context,
    CancellationToken cancellationToken);
}

AuthenticateAsync メソッドは、引数として HttpAuthenticationContext を受け取ります。このコンテキストは、AuthenticateAsync メソッドが、認証プロセスの結果を ASP.NET Web API フレームワークにどのように伝えるかを示しています。要求メッセージに信頼できる資格情報が含まれる場合は、渡された HttpAuthenticationContext オブジェクトの Principal プロパティを認証済みのプリンシパルに設定します。資格情報が無効であれば、HttpAuthenticationContext パラメーターの ErrorResult プロパティを UnauthorizedResult に設定します。要求メッセージに資格情報が含まれていなければ、AuthenticateAsync メソッドは何も実行しません。図 2 のコードは、これら 3 つのシナリオを扱う AuthenticateAsync メソッドの代表的な実装を示しています。この例で使用する認証済みのプリンシパルは、名前と役割の要求だけを含む ClaimsPrincipal です。

図 2 AuthenticateAsync メソッド

public Task AuthenticateAsync(HttpAuthenticationContext context,
  CancellationToken cancellationToken)
{
  var req = context.Request;
  // Get credential from the Authorization header 
  //(if present) and authenticate
  if (req.Headers.Authorization != null &&
    "somescheme".Equals(req.Headers.Authorization.Scheme,
      StringComparison.OrdinalIgnoreCase))
  {
    var creds = req.Headers.Authorization.Parameter;
    if(creds == "opensesame") // Replace with a real check
    {
      var claims = new List<Claim>()
      {
        new Claim(ClaimTypes.Name, "badri"),
        new Claim(ClaimTypes.Role, "admin")
      };
      var id = new ClaimsIdentity(claims, "Token");
      var principal = new ClaimsPrincipal(new[] { id });
      // The request message contains valid credential
      context.Principal = principal;
    }
    else
    {
      // The request message contains invalid credential
      context.ErrorResult = new UnauthorizedResult(
        new AuthenticationHeaderValue[0], context.Request);
    }
  }
  return Task.FromResult(0);
}

AuthenticateAsync メソッドを使用して、要求内の資格情報を検証する中心的な認証ロジックを実装し、ChallengeAsync メソッドを使用して、認証チャレンジを追加します。認証チャレンジは、状態コードが "401 権限がありません" の場合に応答に追加します。そのため、状態コードを調査するには、応答オブジェクトが必要です。しかし、ChallengeAsync メソッドによって、応答を調査したり、チャレンジを直接設定したりできるようにはなりません。実際には、このメソッドは、Web API パイプラインの要求処理部分で、アクション メソッドの前に実行されます。ただし、ChallengeAsync メソッドの HttpAuthenticationChallengeContext パラメーターにより、アクション結果オブジェクト (IHttpActionResult) を Result プロパティに割り当てることができるようになります。アクション結果オブジェクトの ExecuteAsync メソッドは、応答を生成するタスクを待機し、応答状態コードを調べて、WWW-Authenticate 応答ヘッダーを追加します。図 3 のコードは、ChallengeAsync メソッドの代表的な実装を示しています。今回の例では、ハードコードしたチャレンジを追加するだけです。ResultWithChallenge クラスは、チャレンジを追加するために今回作成したアクション結果クラスです。

図 3 ChallengeAsync メソッド

public Task ChallengeAsync(HttpAuthenticationChallengeContext context,
  CancellationToken cancellationToken)
{
  context.Result = new ResultWithChallenge(context.Result);
  return Task.FromResult(0);
}
public class ResultWithChallenge : IHttpActionResult
{
  private readonly IHttpActionResult next;
  public ResultWithChallenge(IHttpActionResult next)
  {
    this.next = next;
  }
  public async Task<HttpResponseMessage> ExecuteAsync(
    CancellationToken cancellationToken)
  {
    var response = await next.ExecuteAsync(cancellationToken);
    if (response.StatusCode == HttpStatusCode.Unauthorized)
    {
      response.Headers.WwwAuthenticate.Add(
        new AuthenticationHeaderValue("somescheme", "somechallenge"));
    }
    return response;
  }
}

次のコードは、完成したフィルター クラスを示します。

public class TokenAuthenticationAttribute : 
  Attribute, IAuthenticationFilter
{
  public bool AllowMultiple { get { return false; } }
  // The AuthenticateAsync and ChallengeAsync methods go here
}

IAuthenticationFilter インターフェイスを実装するだけでなく、クラスを Attribute から派生して、クラス (コントローラー) レベルまたはメソッド (アクション メソッド) レベルでそのクラスを属性として適用できるようにします。

したがって、特定の資格情報 (今回の例では架空のトークン) を認証するという 1 つの役割を持つ認証フィルターを作成できます。認証フィルターに承認ロジックはありません。このフィルターの目的は認証を処理することだけです。ID が存在する場合は ID を確立し (要求メッセージの処理中)、チャレンジが存在する場合はチャレンジを返します (応答メッセージを処理中)。承認フィルターは、ID が認証済みの ID であるかどうか、その ID がユーザーまたは役割の許可リストにあるかどうかを確認するなど、承認の懸念事項を処理します。

承認フィルターの使用

承認フィルターを使用する基本的な目的は承認を実行すること、つまり、要求されたリソースへのアクセスをユーザーに許可するかどうかを判断することです。Web API は、AuthorizeAttribute という承認フィルターの実装を提供します。このフィルターを適用すると、ID が認証済み ID であることが確認されます。また、特定のユーザー名と許可する役割の一覧を含む authorize 属性を構成することもできます。図 4 のコードは、承認する ID のさまざまな属性を使用して、異なるレベル (グローバル、コントローラー レベル、およびアクション メソッド レベル) に適用される承認フィルターを示しています。この例のフィルターは、ID が認証済みであることをグローバルに確認します。コントローラー レベルで使用するフィルターでは、ID が認証済みであること、およびその ID に関連付けられた 1 つ以上の役割が "admin" であることを確認します。アクション メソッド レベルで使用するフィルターでは、ID が認証済みであること、およびユーザー名が "badri" であることを確認します。ここでの注意点は、アクション メソッド レベルの承認フィルターは、コントローラー レベルおよびグローバル レベルからもフィルターを継承することです。したがって、承認を成功させるには、すべてのフィルターで、ユーザー名が "badri" であること、役割の 1 つが "admin" であること、およびユーザーが認証済みであることに合格しなければなりません。

図 4 異なる 3 つのレベルでの承認フィルターの使用

public static class WebApiConfig
{
  public static void Register(HttpConfiguration config)
  {
    // Other Web API configuration code goes here
    config.Filters.Add(new AuthorizeAttribute()); // Global level
  }
}
[Authorize(Roles="admin")] // Controller level
public class EmployeesController : ApiController
{
  [Authorize(Users="badri")] // Action method level
  public string Get(int id)
  {
    return “Hello World”;
  }
}

既定の AuthorizeAttribute は非常に便利ですが、さらにカスタマイズが必要な場合は、それをサブクラス化して追加の承認動作を実装します。次のコードは、カスタム承認フィルターを示しています。

public class RequireAdminClaimAttribute : AuthorizeAttribute
{
  protected override bool IsAuthorized(HttpActionContext context)
  {
    var principal =
      context.Request.GetRequestContext().Principal as ClaimsPrincipal;
    return principal.Claims.Any(c => c.Type ==
      "http://yourschema/identity/claims/admin"
      && c.Value == "true");
  }
}

このフィルターは、"admin" からのカスタム要求かどうかをチェックするだけですが、プリンシパルと、HttpActionContext のその他の追加情報を使用して、カスタム承認を実行できます。

ASP.NET Web API の最初のバージョンでは、認証を実装するためにカスタム承認フィルターが誤って使用されることがよくありましたが、ASP.NET Web API 2 では、認証フィルターはパイプライン内で独自の役割を持ちます。その結果、認証と承認の懸念事項が明確に分離された状態のクリーンなモジュール方式コードを開発できるようになります。

フィルターのオーバーライド

既に説明したとおり、承認フィルターは、アクション メソッド レベル、コントローラー レベル、またはグローバルに適用できます。Authorize フィルターをグローバルに指定することにより、すべてのコントローラーのすべてのアクション メソッド呼び出しに承認を強制できます。グローバルに構成されたチェックからいくつかのメソッドを除外する場合は、AllowAnonymous 属性を使用することで簡単にこれを実現できます。

図 5 のコードは、コントローラー レベルでの AllowAnonymous 属性の使い方を示しています。承認フィルターはグローバルに適用されますが、AllowAnonymous 属性を PublicResourcesController と併用すると、このコントローラーからの要求は承認されなくなります。

図 5 AllowAnonymous 属性の使用

public static class WebApiConfig
{
  public static void Register(HttpConfiguration config)
  {
    // Other Web API configuration code goes here
    config.Filters.Add(new AuthorizeAttribute()); // Global level
  }
}
[AllowAnonymous]
public class PublicResourcesController : ApiController
{
  public string Get(int id)
  {
    return “Hello World”;
  }
}

AllowAnonymous により、特定のアクションが、より高いレベルの承認フィルターによって構成された承認をオーバーライドできるようになります。ただし、AllowAnonymous によってオーバーライドできるようになるのは、承認のみです。ほとんどのアクションでは HTTP 基本認証を使用して認証し、1 つのアクションはトークンだけを使用して認証するとします。この場合は、トークンの認証をグローバルに構成し、AllowAnonymous が承認をオーバーライドするのと同じ方法で、1 つのアクションだけで認証をオーバーライドするようにします。

ASP.NET Web API 2 では、このシナリオに対処するための新しいフィルターの種類としてオーバーライド フィルターが導入されています。AllowAnonymous とは異なり、ASP.NET Web API 2 で導入されたオーバーライド フィルターはどのような種類のフィルターとも連携できます。オーバーライド フィルターは、その名が示すように、より高いレベルで構成されたフィルターをオーバーライドします。より高いレベルで構成された認証フィルターをオーバーライドするには、既定の OverrideAuthentication 属性を使用します。認証フィルターをグローバルに適用していて、そのフィルターが特定のアクション メソッドまたはコントローラーに対して実行されないようにする場合は、必要なレベルで OverrideAuthentication を適用するだけです。

オーバーライド フィルターは、単に特定のフィルターが実行されないようにする場合以外にも役立ちます。たとえば、2 つの認証フィルターがあり、1 つはセキュリティ トークンの認証用、もう 1 つは HTTP 基本スキームでのユーザー名/パスワードの認証用とします。どちらのフィルターもグローバルに適用されるため、API は、トークンまたはユーザー名とパスワードのどちらでも受け取れる柔軟性があります。次のコードは、グローバルに適用された 2 つの認証フィルターを示しています。

public static class WebApiConfig
{
  public static void Register(HttpConfiguration config)
  {
    // Other Web API configuration code goes here
    config.Filters.Add(new TokenAuthenticator());
    config.Filters.Add(new HttpBasicAuthenticator(realm: "Magical"));
  }
}

この場合、おそらく、特定のアクション メソッドにアクセスするための資格情報としてトークンのみを使用したくなります。すべてのフィルターの実行を中止するだけだとすると、OverrideAuthentication によって、このニーズをどのように満たせばよいでしょう。ここでオーバーライド フィルターの重要な特性が役に立ちます。それは、高いレベルで指定されたすべてのフィルターを除外しても、そのフィルターと同レベルで指定されたフィルターは除外しないという特性です。つまり、基本的には、特定のレベルでは 1 つ以上の認証フィルターを追加し、高いレベルの認証フィルターはすべて除外できます。特定のアクション メソッドへのアクセスに資格情報としてトークンだけを使用するという要件に戻ると、次のコードに示すように、アクション メソッド レベルで OverrideAuthentication 属性と TokenAuthenticator を指定するだけです (これにより、GetAllowedForTokenOnly アクション メソッドに対して TokenAuthenticator のみが実行されるようになります)。

public class EmployeesController : ApiController
{
  [OverrideAuthentication] // Removes all authentication filters
  [TokenAuthenticator] // Puts back only the token authenticator
  public string GetAllowedForTokenOnly(int id)
  {
    return “Hello World”;
  }
}

このため、ASP.NET Web API 2 で導入されたオーバーライド フィルターにより、フィルターをグローバルに指定し、グローバルな動作をオーバーライドする必要がある低レベルだけで選択的にフィルターを実行することで、柔軟性が大幅に向上します。

OverrideAuthentication 属性に加えて、OverrideAuthorization という既定の属性もあります。OverrideAuthorization 属性は、より高いレベルで指定された承認フィルターを除外します。AllowAnonymous と比較した場合の違いは、OverrideAuthorization がより高いレベルの承認フィルターのみを除外する点です。同じレベルで指定された承認フィルターは除外しません。AllowAnonymous により、ASP.NET Web API は承認プロセスをまとめてスキップします。AllowAnonymous と同レベルで指定された承認フィルターがある場合でも、これらのフィルターは無視されるだけです。

まとめ

ホストが提供するオプションと ASP.NET Web API パイプラインが提供する拡張ポイントを使用して、ASP.NET Web API に認証を実装できます。ホストベースのオプションは、ホスト パイプラインに適切に統合され、無効な要求をパイプラインの初期段階で拒否できます。ASP.NET Web API の拡張ポイントにより、認証プロセスを細部まで制御できるようになります。認証をさらに細かく制御する必要がある場合 (たとえば、コントローラーやアクション メソッドごとに異なる承認メカニズムを使用する場合) は、認証の懸念事項は認証フィルター、承認の懸念事項は承認フィルターを使って実装するのが優れた方法です。


Badrinarayanan Lakshmiraghavan は、Fortune 500 に名前を連ねる企業のシニア コンサルティング アーキテクトで、『Pro ASP.NET Web API Security』(Apress、2013 年) と『Practical ASP.NET Web API』(Apress、2013 年) の著者です。彼は時折、lbadri.wordpress.com (英語) にブログ記事を投稿することがあります。

この記事のレビューに協力してくれたマイクロソフト技術スタッフの David Matson に心より感謝いたします。
David Matson はマイクロソフトに勤務するソフトウェア開発者です。彼は、MVC 5 および Web API 2 製品チームに所属しています。