次の方法で共有


ASP.NET Core で OpenID Connect Web (UI) 認証を構成する

作成者: Damien Bowden

サンプル コードを表示またはダウンロードする

この記事では、次の領域について説明します。

  • OpenID Connect の機密対話型クライアントとは
  • ASP.NET Core で OpenID Connect クライアントを作成する
  • コード スニペットを使用した OpenID Connect クライアントの例
  • サードパーティの OpenID Connect プロバイダー クライアントの使用
  • フロントエンド (BFF) セキュリティ アーキテクチャのバックエンド
  • OpenID Connect クライアントを拡張する高度な機能、標準

Microsoft Authentication Library for .NETMicrosoft Identity Webおよび Microsoft Entra ID を使用する別のエクスペリエンスについては、「クイック スタート: ユーザーをサインインさせ、ASP.NET Core Web アプリから Microsoft Graph API を呼び出す (Azure ドキュメント)」を参照してください。

Microsoft Entra External ID OIDC サーバーの使用例については、「 外部テナントの Core Web アプリ ASP.NET サンプルのユーザーのサインイン 」と、 Microsoft Identity Web を使用して Microsoft Entra 外部 ID に対してユーザーを認証する ASP.NET Core Web アプリを参照してください。

OpenID Connect の機密対話型クライアントとは

OpenID Connect を使用して、ASP.NET Core アプリケーションに認証を実装できます。 推奨される方法は、コード フローを使用して OpenID Connect 機密クライアントを使用することです。 この実装では、 Proof Key for Code Exchange by OAuth Public Clients (PKCE) を使用することをお勧めします。 アプリケーション クライアントとアプリケーションのユーザーの両方が、機密フローで認証されます。 アプリケーション クライアントは、認証にクライアント シークレットまたはクライアント アサーションを使用します。

パブリック OpenID Connect/OAuth クライアントは、Web アプリケーションでは推奨されなくなりました。

既定のフローは、次の図に示すように機能します。

PKCE を使用した OIDC コード フロー機密クライアント

OpenID Connect にはさまざまなバリエーションがあり、すべてのサーバー実装にはパラメーターと要件が若干異なります。 ユーザー情報エンドポイントをサポートしていないサーバーもあれば、PKCE をサポートしていないサーバーもあれば、トークン要求で特別なパラメーターが必要なサーバーもあります。 クライアント アサーションは、クライアント シークレットの代わりに使用できます。 また、OpenID Connect Core の上にセキュリティを強化する新しい標準 (ダウンストリーム API の FAPI、CIBA、DPoP など) も存在します。

Note

.NET 9 から、OpenID Connect サーバーでサポートされている場合は、既定で OAuth 2.0 プッシュ承認要求 (PAR) RFC 9126 が使用されます。 これは 3 段階のフローであり、上記のような 2 段階のフローではありません。 (ユーザー情報要求は省略可能な手順です)。

Razor Pages を使用して Open ID Connect コード フロー クライアントを作成する

次のセクションでは、空の ASP.NET Core Razor ページ プロジェクトに OpenID Connect クライアントを実装する方法を示します。 UI 統合のみが異なる ASP.NET Core Web プロジェクトにも同じロジックを適用できます。

OpenID Connect のサポートを追加する

Microsoft.AspNetCore.Authentication.OpenIdConnect Nuget パッケージを ASP.NET Core プロジェクトに追加します。

OpenID Connect クライアントをセットアップする

ビルダーを使用して Web アプリケーションに認証を追加します。 Program.cs ファイル内のサービス。 構成は、OpenID Connect サーバーに依存します。 各 OpenID Connect サーバーでは、セットアップに小さな違いが必要です。

OpenID Connect ハンドラーは、チャレンジとサインアウトに使用されます。 cookieは、Web アプリケーションでセッションを処理するために使用されます。 認証の既定のスキームは、必要に応じて指定できます。

詳細については、 ASP.NET Core authentication-handler ガイダンスを参照してください。

builder.Services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
    var oidcConfig = builder.Configuration.GetSection("OpenIDConnectSettings");

    options.Authority = oidcConfig["Authority"];
    options.ClientId = oidcConfig["ClientId"];
    options.ClientSecret = oidcConfig["ClientSecret"];

    options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.ResponseType = OpenIdConnectResponseType.Code;

    options.SaveTokens = true;
    options.GetClaimsFromUserInfoEndpoint = true;

    options.MapInboundClaims = false;
    options.TokenValidationParameters.NameClaimType = JwtRegisteredClaimNames.Name;
    options.TokenValidationParameters.RoleClaimType = "roles";
});

さまざまな OpenID Connect オプションの詳細については、「OpenID Connect (OIDC) を使用して ASP.NET Core Blazor Web App をセキュリティで保護する」を参照してください。

さまざまな要求マッピングの可能性については、「 ASP.NET Core での要求のマッピング、カスタマイズ、および変換」を参照してください。

Note

次の名前空間が必要です。

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;

構成プロパティを設定する

OpenID Connect クライアント設定をアプリケーション構成プロパティに追加します。 この設定は、OpenID Connect サーバーのクライアント構成と一致している必要があります。 シークレットは、誤ってチェックインされる可能性があるアプリケーション設定に保持しないでください。 シークレットは、運用環境の Azure Key Vault などの安全な場所または開発環境のユーザー シークレットに格納する必要があります。 詳細については、「ASP.NET Core での開発におけるアプリ シークレットの安全な保存」を参照してください。

"OpenIDConnectSettings": {
  // OpenID Connect URL. (The base URL for the /.well-known/openid-configuration)
  "Authority": "<Authority>",
  // client ID from the OpenID Connect server
  "ClientId": "<Client ID>",
  //"ClientSecret": "--stored-in-user-secrets-or-key-vault--"
},

サインアウト コールバック パスの構成

SignedOutCallbackPath (構成キー: "SignedOutCallbackPath") は、ユーザー エージェントが ID プロバイダーからサインアウトした後に最初に返される OpenID Connect ハンドラーによってインターセプトされたアプリのベース パス内の要求パスです。 既定値の「/signout-callback-oidc」が使用されるため、サンプル アプリではパスの値は設定されません。 要求をインターセプトした後、OpenID Connect ハンドラーは、指定されている場合は、SignedOutRedirectUri または RedirectUriにリダイレクトします。

アプリの OIDC プロバイダー登録で、サインアウト時のコールバック パスを構成します。 次の例では、 {PORT} のプレースホルダーはアプリのポートです。

https://localhost:{PORT}/signout-callback-oidc

Note

Microsoft Entra ID を使用する場合は、 Entra または Azure portal で Web プラットフォーム構成の リダイレクト URI エントリのパスを設定します。 Entra を使用する場合、localhost アドレスにポートは必要ありません。 他のほとんどの OIDC プロバイダーには、正しいポートが必要です。 Entra でアプリの登録にサインアウト時のコールバック パス URI を追加しない場合、Entra はユーザーをアプリにリダイレクトすることを拒否し、単にブラウザー ウィンドウを閉じるよう要求します。

プログラム クラスの ASP.NET Core パイプライン メソッドを更新します。

UseRouting メソッドは、UseAuthorization メソッドの前に実装する必要があります。

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseRouting();
app.UseAuthentication();
// Authorization is applied for middleware after the UseAuthorization method
app.UseAuthorization();
app.MapRazorPages();

強制的な承認

保護された[Authorize] ページにRazor属性を追加します。

[Authorize]

より良い方法は、アプリ全体の承認を強制し、セキュリティで保護されていないページをオプトアウトすることです。

var requireAuthPolicy = new AuthorizationPolicyBuilder()
    .RequireAuthenticatedUser()
    .Build();

builder.Services.AddAuthorizationBuilder()
    .SetFallbackPolicy(requireAuthPolicy);

パブリック エンドポイントに [AllowAnonymous] 属性 を適用して、パブリック エンドポイントでの承認をオプトアウトします。 例については、「新しいLogout.cshtmlSignedOut.cshtmlRazorページをプロジェクトに追加する」および「Loginページを実装する」セクションを参照してください。

新しい Logout.cshtml ページと SignedOut.cshtmlRazor ページをプロジェクトに追加する

cookie セッションと OpenID Connect セッションの両方をサインアウトするには、ログアウトが必要です。 サインアウトするには、アプリ全体を OpenID Connect サーバーにリダイレクトする必要があります。サインアウトに成功すると、アプリは RedirectUri ルートを開きます。

既定のサインアウト ページを実装し、 Logout Razor ページ コードを次のように変更します。

[Authorize]
public class LogoutModel : PageModel
{
    public IActionResult OnGetAsync()
    {
        return SignOut(new AuthenticationProperties
        {
            RedirectUri = "/SignedOut"
        },
        // Clear auth cookie
        CookieAuthenticationDefaults.AuthenticationScheme,
        // Redirect to OIDC provider signout endpoint
        OpenIdConnectDefaults.AuthenticationScheme);
    }
}

SignedOut.cshtmlには[AllowAnonymous]属性が必要です。

[AllowAnonymous]
public class SignedOutModel : PageModel
{
    public void OnGet()
    {
    }
}

Login ページを実装する

Login Razor ページを実装して、必要なChallengeAsyncを使用してAuthPropertiesを直接呼び出すこともできます。 これは、Web アプリで認証が必要であり、既定のチャレンジが使用されている場合は必要ありません。

Login.cshtml ページには[AllowAnonymous]属性が必要です。

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace RazorPageOidc.Pages;

[AllowAnonymous]
public class LoginModel : PageModel
{
    [BindProperty(SupportsGet = true)]
    public string? ReturnUrl { get; set; }

    public async Task OnGetAsync()
    {
        var properties = GetAuthProperties(ReturnUrl);
        await HttpContext.ChallengeAsync(properties);
    }

    private static AuthenticationProperties GetAuthProperties(string? returnUrl)
    {
        const string pathBase = "/";

        // Prevent open redirects.
        if (string.IsNullOrEmpty(returnUrl))
        {
            returnUrl = pathBase;
        }
        else if (!Uri.IsWellFormedUriString(returnUrl, UriKind.Relative))
        {
            returnUrl = new Uri(returnUrl, UriKind.Absolute).PathAndQuery;
        }
        else if (returnUrl[0] != '/')
        {
            returnUrl = $"{pathBase}{returnUrl}";
        }

        return new AuthenticationProperties { RedirectUri = returnUrl };
    }
}

ユーザーのログインとログアウト ボタンを追加する

@if (Context.User.Identity!.IsAuthenticated)
{
	<li class="nav-item">
		<a class="nav-link text-dark" asp-area="" asp-page="/Logout">Logout</a>
	</li>

	<span class="nav-link text-dark">Hi @Context.User.Identity.Name</span>
}
else
{
	<li class="nav-item">
		<a class="nav-link text-dark" asp-area="" asp-page="/Index">Login</a>
	</li>
}

コード スニペットの例

ユーザー情報エンドポイントの使用例

OpenID Connect オプションを使用すると、要求のマップ、ハンドラーの実装、後で使用するためにセッションにトークンを保存することもできます。

Scope オプションを使用して、OpenID Connect サーバーに情報として送信される別の要求または更新トークンを要求できます。 offline_accessを要求すると、アプリケーションのユーザーを再度認証せずにセッションを更新するために使用できる参照トークンをサーバーに返すように求められます。

services.AddAuthentication(options =>
{
    options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
    options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
    var oidcConfig = builder.Configuration.GetSection("OpenIDConnectSettings");
    options.Authority = oidcConfig["IdentityProviderUrl"];
    options.ClientSecret = oidcConfig["ClientSecret"];
    options.ClientId = oidcConfig["Audience"];
    options.ResponseType = OpenIdConnectResponseType.Code;

    options.Scope.Clear();
    options.Scope.Add("openid");
    options.Scope.Add("profile");
    options.Scope.Add("email");
    options.Scope.Add("offline_access");

    options.ClaimActions.Remove("amr");
    options.ClaimActions.MapUniqueJsonKey("website", "website");

    options.GetClaimsFromUserInfoEndpoint = true;
    options.SaveTokens = true;

    // .NET 9 feature
    options.PushedAuthorizationBehavior = PushedAuthorizationBehavior.Require;

    options.TokenValidationParameters.NameClaimType = "name";
    options.TokenValidationParameters.RoleClaimType = "role";
});

Microsoft ID プロバイダーの実装

Microsoft には、複数の ID プロバイダーと OpenID Connect 実装があります。 Microsoft には、さまざまな OpenID Connect サーバーがあります。

  • Microsoft Entra ID
  • Microsoft Entra 外部 ID
  • Azure AD B2C

ASP.NET Core の Microsoft ID プロバイダーのいずれかを使用して認証する場合は、 Microsoft.Identity.Web Nuget パッケージを使用することをお勧めします。

Microsoft.Identity.Web Nuget パッケージは、ASP.NET Core OpenID Connect クライアント上に構築された Microsoft 固有のクライアントであり、既定のクライアントにいくつかの変更が加えられます。

サードパーティの OpenID Connect プロバイダー クライアントの使用

多くの OpenID Connect サーバー実装では、同じ OpenID Connect 実装用に最適化された Nuget パッケージが作成されます。 これらのパッケージは、特定の OpenID Connect サーバーに必要な追加機能を備えた OpenID Connect クライアント固有のパッケージを実装します。 Microsoft.Identity.Web は、この例の 1 つです。

1 つのアプリケーションで異なる OpenID Connect サーバーから複数の OpenID Connect クライアントを実装する場合は、通常、異なるクライアントが他のクライアントに影響を与える一部のオプションを上書きするため、既定の ASP.NET Core 実装に戻す方が適切です。

OpenIddict Web プロバイダー は、さまざまなサーバー実装をサポートするクライアント実装です。

IdentityModel は、クレーム ベースの ID、OAuth 2.0、および OpenID Connect 用の .NET 標準ヘルパー ライブラリです。 これは、クライアントの実装に役立つ場合にも使用できます。

フロントエンド (BFF) セキュリティ アーキテクチャのバックエンド

Web アプリ用に OpenID Connect パブリック クライアントを実装することは推奨されなくなりました。

詳細については、 Browser-Based アプリケーションの OAuth 2.0 のドラフトを参照してください。

独立したバックエンドがない Web アプリケーションを実装する場合は、 バックエンド for フロントエンド (BFF) パターン のセキュリティ アーキテクチャを使用することをお勧めします。 このパターンはさまざまな方法で実装できますが、認証は常にバックエンドに実装され、さらに承認または認証フローのために機密データは Web クライアントに送信されません。

OIDC クライアントを拡張する高度な機能、標準

ログ

OpenID Connect クライアントのデバッグは困難な場合があります。 個人を特定できる情報 (PII) データは、既定ではログに記録されません。 開発モードでデバッグする場合は、 IdentityModelEventSource.ShowPII を使用して機密性の高い個人データをログに記録できます。 IdentityModelEventSource.ShowPIIを含むアプリを生産性の高いサーバーにデプロイしないでください。

//using ...

using Microsoft.IdentityModel.Logging;

var builder = WebApplication.CreateBuilder(args);

//... code 

var app = builder.Build();

IdentityModelEventSource.ShowPII = true;

//... code 

app.Run();

詳細については、「ログ」を参照してください。

Note

構成済みのログ レベルを下げて、必要なすべてのログを表示できます。

OIDC と OAuth パラメーターのカスタマイズ

OAuth および OIDC 認証ハンドラー (AdditionalAuthorizationParameters) オプションを使用すると、通常はリダイレクト クエリ文字列の一部として含まれる承認メッセージ パラメーターをカスタマイズできます。

OpenID Connect からの要求をマップする

詳細については、「 ASP.NET Core での要求のマッピング、カスタマイズ、および変換」を参照してください。

Blazor OpenID Connect

詳細については、「 OpenID Connect (OIDC) を使用して ASP.NET Core Blazor Web App をセキュリティで保護する」を参照してください。

標準