次の方法で共有


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

作成者: Damien Bowden

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

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

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

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](xref: security/authentication/index?view=aspnetcore-8.0#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 などの安全な場所または開発環境のユーザー シークレットに格納する必要があります。 「 App シークレットを参照してください。

"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--"
},

プログラム クラスの 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();

強制的な承認

保護された razor ページに Authorize 属性を追加します (Index.cshtml.cs ファイルなど)

[Authorize]

より良い方法は、アプリケーション全体を強制的に承認し、安全でないページをオプトアウトすることです

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

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

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

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

既定のサインアウト ページを実装し、次の方法でログアウト 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()
    {
    }
}

ログイン ページを実装する

ログイン 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 identity プロバイダーの実装

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

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

ASP.NET Core で Microsoft identity プロバイダーのいずれかを使用して認証する場合は、 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 は、クレーム ベースの identity、OAuth 2.0、および OpenID Connect 用の .NET 標準ヘルパー ライブラリです。 これは、クライアントの実装に役立つ場合にも使用できます。

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

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

詳細については、ブラウザー ベースのアプリケーションの draft OAuth 2.0 を参照してください。

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

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

ログ

OpenID Connect クライアントのデバッグは困難な場合があります。 個人を特定できる情報 (PII) データは、既定ではログに記録されません。 開発モードでデバッグする場合は、** 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 をセキュリティで保護する

標準

OpenID Connect 1.0

OAuth パブリック クライアントによるコード交換の証明キー

OAuth 2.0 承認フレームワーク

OAuth 2.0 プッシュ承認要求 (PAR) RFC 9126