メインコンテンツまでスキップ

あなたの .NET Core (Blazor WASM) アプリケーションに認証 (Authentication) を追加する

ヒント:
  • 以下のデモンストレーションは、.NET Core 8.0 と Blorc.OpenIdConnect に基づいて構築されています。
  • .NET Core のサンプルプロジェクトは GitHub リポジトリ で入手可能です。

前提条件

インストール

プロジェクトに NuGet パッケージを追加します:

dotnet add package Blorc.OpenIdConnect

統合

スクリプト参照を追加する

index.html ファイルに Blorc.Core/injector.js を含めます:

index.html
<head>
<!-- ... -->
<script src="_content/Blorc.Core/injector.js"></script>
<!-- ... -->
</head>

サービスを登録する

次のコードを Program.cs ファイルに追加します:

Program.cs
using Blorc.OpenIdConnect;
using Blorc.Services;

builder.Services.AddBlorcCore();
builder.Services.AddAuthorizationCore();
builder.Services.AddBlorcOpenIdConnect(
options =>
{
builder.Configuration.Bind("IdentityServer", options);
});

var webAssemblyHost = builder.Build();

await webAssemblyHost
.ConfigureDocumentAsync(async documentService =>
{
await documentService.InjectBlorcCoreJsAsync();
await documentService.InjectOpenIdConnectAsync();
});

await webAssemblyHost.RunAsync();
備考:

Microsoft.AspNetCore.Components.WebAssembly.Authentication パッケージを使用する必要はありません。Blorc.OpenIdConnect パッケージが認証 (Authentication) プロセスを処理します。

リダイレクト URI を設定する

詳細に入る前に、エンドユーザー体験の概要を簡単にご紹介します。サインインプロセスは次のようにシンプルにまとめられます:

  1. アプリがサインインメソッドを呼び出します。
  2. ユーザーは Logto のサインインページにリダイレクトされます。ネイティブアプリの場合は、システムブラウザが開かれます。
  3. ユーザーがサインインし、アプリ(リダイレクト URI として設定)に戻されます。

リダイレクトベースのサインインについて

  1. この認証 (Authentication) プロセスは OpenID Connect (OIDC) プロトコルに従い、Logto はユーザーのサインインを保護するために厳格なセキュリティ対策を講じています。
  2. 複数のアプリがある場合、同じアイデンティティプロバイダー (Logto) を使用できます。ユーザーがあるアプリにサインインすると、Logto は別のアプリにアクセスした際に自動的にサインインプロセスを完了します。

リダイレクトベースのサインインの理論と利点について詳しく知るには、Logto サインイン体験の説明を参照してください。


注記:

以下のコードスニペットでは、あなたのアプリが http://localhost:3000/ で実行されていると仮定しています。

リダイレクト URI を設定する

Logto Console のアプリケーション詳細ページに移動します。リダイレクト URI http://localhost:3000/callback を追加します。

Logto Console のリダイレクト URI

サインインと同様に、ユーザーは共有セッションからサインアウトするために Logto にリダイレクトされるべきです。完了したら、ユーザーをあなたのウェブサイトに戻すと良いでしょう。例えば、http://localhost:3000/ をサインアウト後のリダイレクト URI セクションとして追加します。

その後、「保存」をクリックして変更を保存します。

アプリケーションを設定する

次のコードを appsettings.json ファイルに追加します:

appsettings.json
{
// ...
IdentityServer: {
Authority: 'https://<your-logto-endpoint>/oidc',
ClientId: '<your-logto-app-id>',
PostLogoutRedirectUri: 'http://localhost:3000/',
RedirectUri: 'http://localhost:3000/callback',
ResponseType: 'code',
Scope: 'openid profile', // 必要に応じてスコープを追加
},
}

RedirectUriPostLogoutRedirectUri を Logto アプリケーション設定の許可されたリダイレクト URI のリストに追加することを忘れないでください。これらはどちらも WASM アプリケーションの URL です。

AuthorizeView コンポーネントを追加する

認証 (Authentication) が必要な Razor ページに AuthorizeView コンポーネントを追加します。Home.razor ページであると仮定します:

Pages/Home.razor
@using Microsoft.AspNetCore.Components.Authorization
@page "/"

<AuthorizeView>
<Authorized>
@* サインイン済みビュー *@
<button @onclick="OnLogoutButtonClickAsync">
サインアウト
</button>
</Authorized>
<NotAuthorized>
@* 未認証ビュー *@
<button @onclick="OnLoginButtonClickAsync">
サインイン
</button>
</NotAuthorized>
</AuthorizeView>

認証 (Authentication) を設定する

Home.razor.cs ファイルに(存在しない場合は作成して)次のコードを追加します:

Pages/Home.razor.cs
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Components.Web;
using Blorc.OpenIdConnect;
using Microsoft.AspNetCore.Components.Authorization;

[Authorize]
public partial class Home : ComponentBase
{
[Inject]
public required IUserManager UserManager { get; set; }

public User<Profile>? User { get; set; }

[CascadingParameter]
protected Task<AuthenticationState>? AuthenticationStateTask { get; set; }

protected override async Task OnInitializedAsync()
{
User = await UserManager.GetUserAsync<User<Profile>>(AuthenticationStateTask!);
}

private async Task OnLoginButtonClickAsync(MouseEventArgs obj)
{
await UserManager.SignInRedirectAsync();
}

private async Task OnLogoutButtonClickAsync(MouseEventArgs obj)
{
await UserManager.SignOutRedirectAsync();
}
}

ユーザーが認証 (Authentication) されると、User プロパティにユーザー情報が設定されます。

チェックポイント: アプリケーションをテストする

これで、アプリケーションをテストできます:

  1. アプリケーションを実行すると、サインインボタンが表示されます。
  2. サインインボタンをクリックすると、SDK がサインインプロセスを初期化し、Logto のサインインページにリダイレクトされます。
  3. サインインすると、アプリケーションに戻り、サインアウトボタンが表示されます。
  4. サインアウトボタンをクリックして、トークンストレージをクリアし、サインアウトします。

ユーザー情報の取得

ユーザー情報を表示する

Home.razor ページでユーザー情報を表示する方法の例をいくつか示します:

<AuthorizeView>
<Authorized>
@* サインイン済みビュー *@
@* ... *@
<p>あなたは @(@User?.Profile?.Name ?? "(unknown name)") としてサインインしています。</p>
</Authorized>
@* ... *@
</AuthorizeView>

より多くのプロパティとクレームについては、Blorc.OpenIdConnect パッケージの UserProfile クラスを確認してください。

追加のクレームをリクエストする

User から返されるオブジェクトに一部のユーザー情報が欠けていることがあります。これは、OAuth 2.0 と OpenID Connect (OIDC) が最小特権の原則 (PoLP) に従うように設計されており、Logto はこれらの標準に基づいて構築されているためです。

デフォルトでは、限られたクレーム (Claims) が返されます。より多くの情報が必要な場合は、追加のスコープ (Scopes) をリクエストして、より多くのクレーム (Claims) にアクセスできます。

備考:

「クレーム (Claim)」はサブジェクトについての主張であり、「スコープ (Scope)」はクレーム (Claims) のグループです。現在のケースでは、クレーム (Claim) はユーザーに関する情報の一部です。

スコープ (Scope) とクレーム (Claim) の関係の非規範的な例を示します:

ヒント:

「sub」クレーム (Claim) は「サブジェクト (Subject)」を意味し、ユーザーの一意の識別子(つまり、ユーザー ID)です。

Logto SDK は常に 3 つのスコープ (Scopes) をリクエストします:openidprofile、および offline_access

追加のスコープをリクエストするには、有効なスコープを appsettings.json ファイルの IdentityServer.Scope プロパティに追加できます。

{
// ...
"IdentityServer": {
// ...
"Scope": "openid profile email phone"
}
}

ネットワークリクエストが必要なクレーム

ユーザーオブジェクトの肥大化を防ぐために、一部のクレームは取得するためにネットワークリクエストが必要です。例えば、custom_data クレームはスコープでリクエストされていてもユーザーオブジェクトには含まれません。これらのクレームを取得するには、appsettings.json ファイルで IdentityServer.LoadUserInfo プロパティを true に設定できます。

例えば、ユーザーのメールアドレスとカスタムデータを取得するには、次の設定を使用できます:

{
// ...
"IdentityServer": {
// ...
"Scope": "openid profile email custom_data",
"LoadUserInfo": true
}
}

スコープとクレーム

Logto は OIDC の スコープ (Scope) とクレーム (Claim) の規約 を使用して、ID トークンおよび OIDC userinfo エンドポイント からユーザー情報を取得するためのスコープ (Scope) とクレーム (Claim) を定義しています。「スコープ (Scope)」と「クレーム (Claim)」は、OAuth 2.0 および OpenID Connect (OIDC) 仕様の用語です。

標準の OIDC クレーム (Claim) については、ID トークンへの含有はリクエストされたスコープ (Scope) によって厳密に決定されます。拡張クレーム (Claim)(例:custom_dataorganizations)は、カスタム ID トークン 設定を通じて ID トークンに追加で表示するように構成できます。

こちらはサポートされているスコープと対応するクレーム (Claims) の一覧です:

標準 OIDC スコープ

openid(デフォルト)

Claim nameType説明
substringユーザーの一意の識別子

profile(デフォルト)

Claim nameType説明
namestringユーザーのフルネーム
usernamestringユーザー名
picturestringエンドユーザーのプロフィール画像の URL。この URL は画像ファイル(例:PNG、JPEG、GIF 画像ファイル)を指す必要があり、画像を含む Web ページではありません。この URL は、エンドユーザーを説明する際に表示するのに適したプロフィール写真を特に参照するべきであり、エンドユーザーが撮影した任意の写真ではありません。
created_atnumberエンドユーザーが作成された時刻。Unix エポック(1970-01-01T00:00:00Z)からのミリ秒数で表されます。
updated_atnumberエンドユーザー情報が最後に更新された時刻。Unix エポック(1970-01-01T00:00:00Z)からのミリ秒数で表されます。

その他の 標準クレーム (Standard Claims) には、family_namegiven_namemiddle_namenicknamepreferred_usernameprofilewebsitegenderbirthdatezoneinfolocale などがあり、これらも profile スコープに含まれます(userinfo エンドポイントをリクエストする必要はありません)。上記のクレームとの違いは、これらのクレームは値が空でない場合のみ返される点です。一方、上記のクレームは値が空の場合 null が返されます。

注記:

標準クレーム (Standard Claims) とは異なり、created_at および updated_at クレームは秒ではなくミリ秒を使用しています。

email

Claim nameType説明
emailstringユーザーのメールアドレス
email_verifiedbooleanメールアドレスが認証済みかどうか

phone

Claim nameType説明
phone_numberstringユーザーの電話番号
phone_number_verifiedboolean電話番号が認証済みかどうか

address

アドレスクレームの詳細については OpenID Connect Core 1.0 を参照してください。

備考:

(デフォルト) と記載されたスコープは常に Logto SDK によってリクエストされます。標準 OIDC スコープ下のクレーム (Claims) は、対応するスコープがリクエストされた場合、常に ID トークン (ID token) に含まれます — 無効化できません。

拡張スコープ

以下のスコープは Logto によって拡張されており、userinfo エンドポイント を通じてクレーム (Claims) を返します。これらのクレームは Console > Custom JWT を通じて ID トークン (ID token) に直接含めるよう設定することもできます。詳細は カスタム ID トークン を参照してください。

custom_data

Claim nameType説明デフォルトで ID トークンに含まれるか
custom_dataobjectユーザーのカスタムデータ

identities

Claim nameType説明デフォルトで ID トークンに含まれるか
identitiesobjectユーザーのリンク済みアイデンティティ
sso_identitiesarrayユーザーのリンク済み SSO アイデンティティ

roles

Claim nameType説明デフォルトで ID トークンに含まれるか
rolesstring[]ユーザーのロール

urn:logto:scope:organizations

Claim nameType説明デフォルトで ID トークンに含まれるか
organizationsstring[]ユーザーが所属する組織 ID
organization_dataobject[]ユーザーが所属する組織データ
注記:

これらの組織クレーム (Organization Claims) は、不透明トークン (Opaque token) を使用している場合でも userinfo エンドポイント経由で取得できます。ただし、不透明トークン (Opaque token) は組織トークン (Organization token) として組織固有リソースへのアクセスには使用できません。詳細は 不透明トークン (Opaque token) と組織 (Organizations) を参照してください。

urn:logto:scope:organization_roles

Claim nameType説明デフォルトで ID トークンに含まれるか
organization_rolesstring[]ユーザーが所属する組織ロール(<organization_id>:<role_name> 形式)

API リソース

まず 🔐 ロールベースのアクセス制御 (RBAC) を読むことをお勧めします。これにより、Logto の RBAC の基本概念と API リソースを適切に設定する方法を理解できます。

デフォルトでは、User?.AccessToken にアクセスすると、短い長さの不透明トークン (Opaque token) が取得されます。これは JWT (JSON Web Token) ではありません。このトークンは userinfo エンドポイントへのアクセスに使用されます。

API リソースを設定に追加する

Logto で定義された API リソースにアクセスできる JWT を取得するには、appsettings.json ファイルに次のパラメーターを追加します(例として https://my-api-resource を使用):

appsettings.json
{
// ...
"IdentityServer": {
// ...
"Scope": "openid profile email <your-api-scopes>", // ここに API スコープを追加
"Resource": "https://my-api-resource",
"ExtraTokenParams": {
"resource": "https://my-api-resource" // キー "resource" は小文字であることを確認
}
}
}

Resource プロパティは認証リクエストに API リソースを追加するために使用します。ExtraTokenParams プロパティはトークンリクエストに API リソースを追加するために使用します。Logto は API リソースに関して RFC 8707 に準拠しているため、両方のプロパティが必要です。

注意:

WebAssembly はクライアントサイドアプリケーションであるため、トークンリクエストはサーバーサイドに一度だけ送信されます。この特性により、LoadUserInfo は API リソース用のアクセス トークン (Access token) の取得と競合します。

アクセス トークン (Access token) を利用する

ユーザーが認証 (Authentication) されると、User?.AccessToken プロパティを使用して API リソースにアクセスできます。例えば、HttpClient を使って API リソースにアクセスできます:

using Blorc.OpenIdConnect;

builder.Services
.AddHttpClient("MyApiResource", client =>
{
client.BaseAddress = new Uri("https://my-api-resource");
})
.AddAccessToken(); // リクエストヘッダーにアクセス トークン (Access token) を追加

さらなる読み物

エンドユーザーフロー:認証 (Authentication) フロー、アカウントフロー、組織フロー コネクターの設定 認可 (Authorization)