ASP.NET Core の Identity の概要

作成者: Rick Anderson

ASP.NET Core Identity:

  • ユーザー インターフェイス (UI) ログイン機能をサポートする API です。
  • ユーザー、パスワード、プロファイル データ、ロール、要求、トークン、電子メールの確認などを管理します。

ユーザーは、Identity に格納されているログイン情報を使用してアカウントを作成することができます。あるいは、外部ログイン プロバイダーを使用できます。 サポートされている外部ログイン プロバイダーには、Facebook、Google、Microsoft アカウント、Twitter があります。

すべてのユーザーの認証をグローバルに要求する方法の詳細については、「認証されたユーザーを要求する」を参照してください。

Identity ソース コードは GitHub で入手できます。 Identity をスキャフォールディングし、生成されたファイルを表示してテンプレートと Identity とのやりとりを確認します。

Identity は通常、ユーザー名、パスワード、およびプロファイル データを格納するために SQL Server データベースを使用して構成されます。 別の固定ストア (たとえば、Azure Table Storage) を使用することもできます。

このトピックでは、Identity を使用して、ユーザーの登録、ログイン、およびログアウトを行う方法について学習します。 注: テンプレートでは、ユーザーのユーザー名と電子メールを同じものとして扱います。 Identity を使用するアプリの作成に関する詳細な手順については、「次の手順」を参照してください。

ASP.NET Core Identity は、Microsoft identity プラットフォームとは関係ありません。 Microsoft identity プラットフォーは、

  • Azure Active Directory (Azure AD) 開発者プラットフォームが進化したものです。
  • ASP.NET Core アプリでの認証と認可のための代替 identity ソリューションです。

ASP.NET Core Identity では、ASP.NET Core Web アプリにユーザー インターフェイス (UI) ログイン機能が追加されます。 Web API と SPA をセキュリティで保護するには、次のいずれかを使用します。

Duende Identity Server は、ASP.NET Core 用の OpenID Connect および OAuth 2.0 フレームワークです。 Duende Identity Server により、次のセキュリティ機能が有効になります。

  • サービスとしての認証 (AaaS)
  • 複数のアプリケーションの種類でのシングル サインオン/オフ (SSO)
  • API のアクセス制御
  • Federation Gateway

重要

Duende Software により、Duende Identity Server を実稼働で使用することのライセンス料の支払いが求められる場合があります。 詳細については、「ASP.NET Core 5.0 から 6.0 への移行」を参照してください。

詳細については、Duende Identity Server に関するドキュメント (Duende ソフトウェアの Web サイト) を参照してください。

サンプル コードを表示またはダウンロードします (ダウンロード方法)。

認証を使用して Web アプリを作成する

個々のユーザー アカウントを使用して、ASP.NET Core Web アプリケーション プロジェクトを作成します。

  • [ASP.NET Core Web アプリ] テンプレートを選択します。 プロジェクトに WebApp1 という名前を付け、プロジェクトのダウンロードと同じ名前空間を使用します。 [OK] をクリックします。
  • [認証の種類] の入力で、[個々のユーザー アカウント] を選択します。

生成されたプロジェクトによって、ASP.NET CoreIdentityRazor クラス ライブラリとして提供されます。 IdentityRazor クラス ライブラリにより、Identity 領域でエンドポイントが公開されます。 次に例を示します。

  • /Identity/Account/Login
  • /Identity/Account/Logout
  • /Identity/Account/Manage

移行を適用する

移行を適用してデータベースを初期化します。

パッケージ マネージャー コンソール (PMC) で次のコマンドを実行します。

Update-Database

登録とログインをテストする

アプリを実行し、ユーザーを登録します。 ご利用の画面のサイズによっては、ナビゲーション トグル ボタンを選択して [登録] および [ログイン] リンクを表示する必要がある場合があります。

Identity データベースを表示する

  • [表示] メニューから [SQL Server オブジェクト エクスプローラー] (SSOX) を選択します。
  • (localdb)MSSQLLocalDB(SQL Server 13) に移動します。 dbo.AspNetUsers>View Data を右クリックします。

SQL Server オブジェクト エクスプローラーの AspNetUsers テーブルのコンテキスト メニュー

Identity サービスを構成する

サービスは Program.cs に追加されます。 一般的なパターンは、次の順序でメソッドを呼び出すことです。

  1. Add{Service}
  2. builder.Services.Configure{Service}
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;
using WebApp1.Data;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();
builder.Services.AddRazorPages();

builder.Services.Configure<IdentityOptions>(options =>
{
    // Password settings.
    options.Password.RequireDigit = true;
    options.Password.RequireLowercase = true;
    options.Password.RequireNonAlphanumeric = true;
    options.Password.RequireUppercase = true;
    options.Password.RequiredLength = 6;
    options.Password.RequiredUniqueChars = 1;

    // Lockout settings.
    options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
    options.Lockout.MaxFailedAccessAttempts = 5;
    options.Lockout.AllowedForNewUsers = true;

    // User settings.
    options.User.AllowedUserNameCharacters =
    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
    options.User.RequireUniqueEmail = false;
});

builder.Services.ConfigureApplicationCookie(options =>
{
    // Cookie settings
    options.Cookie.HttpOnly = true;
    options.ExpireTimeSpan = TimeSpan.FromMinutes(5);

    options.LoginPath = "/Identity/Account/Login";
    options.AccessDeniedPath = "/Identity/Account/AccessDenied";
    options.SlidingExpiration = true;
});

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    app.UseHsts();
}

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

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

app.MapRazorPages();

app.Run();

前のコードでは、既定のオプション値で Identity を構成します。 サービスは、依存性の挿入を介してアプリで使用できるようになります。

Identity は、UseAuthentication を呼び出すことによって有効になります。 UseAuthentication では、要求パイプラインに認証ミドルウェアを追加します。

テンプレートで生成されたアプリでは、承認は使用されません。 app.UseAuthorization は、アプリで承認が追加された場合に確実に正しい順序で追加されるようにするために含まれています。 UseRoutingUseAuthenticationUseAuthorization は、前のコードに示されている順序で呼び出す必要があります。

IdentityOptions の詳細については、「IdentityOptions」およびアプリケーションの起動に関するページを参照してください。

Register、Login、LogOut、および RegisterConfirmation をスキャフォールディングする

RegisterLoginLogOut、および RegisterConfirmation ファイルを追加します。 「承認を使用して Razor プロジェクトに identity をスキャフォールディングする 」の手順に従って、このセクションに示されているコードを生成します。

登録を確認する

ユーザーが Register ページの [登録] ボタンをクリックすると、RegisterModel.OnPostAsync アクションが呼び出されます。 ユーザーは、_userManager オブジェクトで CreateAsync(TUser) によって作成されます。

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");
    ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync())
                                          .ToList();
    if (ModelState.IsValid)
    {
        var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
        var result = await _userManager.CreateAsync(user, Input.Password);
        if (result.Succeeded)
        {
            _logger.LogInformation("User created a new account with password.");

            var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
            code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
            var callbackUrl = Url.Page(
                "/Account/ConfirmEmail",
                pageHandler: null,
                values: new { area = "Identity", userId = user.Id, code = code },
                protocol: Request.Scheme);

            await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
                $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");

            if (_userManager.Options.SignIn.RequireConfirmedAccount)
            {
                return RedirectToPage("RegisterConfirmation", 
                                      new { email = Input.Email });
            }
            else
            {
                await _signInManager.SignInAsync(user, isPersistent: false);
                return LocalRedirect(returnUrl);
            }
        }
        foreach (var error in result.Errors)
        {
            ModelState.AddModelError(string.Empty, error.Description);
        }
    }

    // If we got this far, something failed, redisplay form
    return Page();
}

既定のアカウント検証を無効にする

既定のテンプレートでは、ユーザーは Account.RegisterConfirmation にリダイレクトされ、アカウントを確認するリンクを選択できます。 既定値 Account.RegisterConfirmation は、テスト目的で "のみ" 使用されます。運用アプリでは、自動アカウント検証を無効にしてください。

確認済みのアカウントを必須にして、登録時に即時ログインできないようにするには、/Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.csDisplayConfirmAccountLink = false を設定します。

[AllowAnonymous]
public class RegisterConfirmationModel : PageModel
{
    private readonly UserManager<IdentityUser> _userManager;
    private readonly IEmailSender _sender;

    public RegisterConfirmationModel(UserManager<IdentityUser> userManager, IEmailSender sender)
    {
        _userManager = userManager;
        _sender = sender;
    }

    public string Email { get; set; }

    public bool DisplayConfirmAccountLink { get; set; }

    public string EmailConfirmationUrl { get; set; }

    public async Task<IActionResult> OnGetAsync(string email, string returnUrl = null)
    {
        if (email == null)
        {
            return RedirectToPage("/Index");
        }

        var user = await _userManager.FindByEmailAsync(email);
        if (user == null)
        {
            return NotFound($"Unable to load user with email '{email}'.");
        }

        Email = email;
        // Once you add a real email sender, you should remove this code that lets you confirm the account
        DisplayConfirmAccountLink = false;
        if (DisplayConfirmAccountLink)
        {
            var userId = await _userManager.GetUserIdAsync(user);
            var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
            code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
            EmailConfirmationUrl = Url.Page(
                "/Account/ConfirmEmail",
                pageHandler: null,
                values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
                protocol: Request.Scheme);
        }

        return Page();
    }
}

ログイン

ログイン フォームは次の場合に表示されます。

  • [ログイン] リンクが選択されている。
  • ユーザーが、アクセスを承認されていない、またはシステムによって認証されていない場合に、制限付きページにアクセスしようとした。

[ログイン] ページのフォームが送信されると、OnPostAsync アクションが呼び出されます。 PasswordSignInAsync_signInManager オブジェクトで呼び出されます。

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");

    if (ModelState.IsValid)
    {
        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, 
        // set lockoutOnFailure: true
        var result = await _signInManager.PasswordSignInAsync(Input.Email,
                           Input.Password, Input.RememberMe, lockoutOnFailure: true);
        if (result.Succeeded)
        {
            _logger.LogInformation("User logged in.");
            return LocalRedirect(returnUrl);
        }
        if (result.RequiresTwoFactor)
        {
            return RedirectToPage("./LoginWith2fa", new
            {
                ReturnUrl = returnUrl,
                RememberMe = Input.RememberMe
            });
        }
        if (result.IsLockedOut)
        {
            _logger.LogWarning("User account locked out.");
            return RedirectToPage("./Lockout");
        }
        else
        {
            ModelState.AddModelError(string.Empty, "Invalid login attempt.");
            return Page();
        }
    }

    // If we got this far, something failed, redisplay form
    return Page();
}

承認の決定を行う方法に関する詳細については、「ASP.NET Core での認可の概要」を参照してください。

ログアウト

[ログアウト] リンクによって LogoutModel.OnPost アクションが呼び出されます。

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;

namespace WebApp1.Areas.Identity.Pages.Account
{
    [AllowAnonymous]
    public class LogoutModel : PageModel
    {
        private readonly SignInManager<IdentityUser> _signInManager;
        private readonly ILogger<LogoutModel> _logger;

        public LogoutModel(SignInManager<IdentityUser> signInManager, ILogger<LogoutModel> logger)
        {
            _signInManager = signInManager;
            _logger = logger;
        }

        public void OnGet()
        {
        }

        public async Task<IActionResult> OnPost(string returnUrl = null)
        {
            await _signInManager.SignOutAsync();
            _logger.LogInformation("User logged out.");
            if (returnUrl != null)
            {
                return LocalRedirect(returnUrl);
            }
            else
            {
                return RedirectToPage();
            }
        }
    }
}

前のコードでは、ブラウザーで新しい要求が実行され、ユーザーの identity が更新されるように、コード return RedirectToPage(); をリダイレクトする必要があります。

SignOutAsync により、cookie に格納されているユーザーのクレームがクリアされます。

post は、Pages/Shared/_LoginPartial.cshtml で指定されます。

@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager

<ul class="navbar-nav">
@if (SignInManager.IsSignedIn(User))
{
    <li class="nav-item">
        <a  class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index" 
                                              title="Manage">Hello @User.Identity.Name!</a>
    </li>
    <li class="nav-item">
        <form class="form-inline" asp-area="Identity" asp-page="/Account/Logout" 
                                  asp-route-returnUrl="@Url.Page("/", new { area = "" })" 
                                  method="post" >
            <button  type="submit" class="nav-link btn btn-link text-dark">Logout</button>
        </form>
    </li>
}
else
{
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Register">Register</a>
    </li>
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Login">Login</a>
    </li>
}
</ul>

Identity をテストする

既定の Web プロジェクト テンプレートでは、home ページへの匿名アクセスが許可されます。 Identity をテストするには、[Authorize] を追加します。

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;

namespace WebApp1.Pages
{
    [Authorize]
    public class PrivacyModel : PageModel
    {
        private readonly ILogger<PrivacyModel> _logger;

        public PrivacyModel(ILogger<PrivacyModel> logger)
        {
            _logger = logger;
        }

        public void OnGet()
        {
        }
    }
}

サインインしている場合は、サインアウトします。アプリを実行し、Privacy リンクを選択します。 ログイン ページにリダイレクトされます。

Identity を調べる

Identity をさらに詳しく調べるには、次のようにします。

Identity のコンポーネント

Identity に依存するすべての NuGet パッケージは、ASP.NET Core 共有フレームワークに含まれています。

Identity のプライマリ パッケージは Microsoft.AspNetCore.Identity です。 このパッケージには、ASP.NET Core Identity 用のインターフェイスのコア セットが含まれており、Microsoft.AspNetCore.Identity.EntityFrameworkCore によって含められます。

ASP.NET Core Identity への移行

既存の Identity ストアの移行に関する詳細とガイダンスについては、認証と Identity の移行に関するページを参照してください。

パスワードの強度の設定

パスワードの最小要件を設定するサンプルについては、「構成」を参照してください。

AddDefaultIdentity と AddIdentity

AddDefaultIdentity は ASP.NET Core 2.1 で導入されました。 AddDefaultIdentity の呼び出しは次の呼び出しに似ています。

詳細については、「AddDefaultIdentity ソース」を参照してください。

静的 Identity アセットを発行しないようにする

静的 Identity アセット (Identity UI 用のスタイルシートと JavaScript ファイル) が Web ルートに発行されるのを防ぐには、次の ResolveStaticWebAssetsInputsDependsOn プロパティと RemoveIdentityAssets ターゲットをアプリのプロジェクト ファイルに追加します。

<PropertyGroup>
  <ResolveStaticWebAssetsInputsDependsOn>RemoveIdentityAssets</ResolveStaticWebAssetsInputsDependsOn>
</PropertyGroup>

<Target Name="RemoveIdentityAssets">
  <ItemGroup>
    <StaticWebAsset Remove="@(StaticWebAsset)" Condition="%(SourceId) == 'Microsoft.AspNetCore.Identity.UI'" />
  </ItemGroup>
</Target>

次の手順

作成者: Rick Anderson

ASP.NET Core Identity:

  • ユーザー インターフェイス (UI) ログイン機能をサポートする API です。
  • ユーザー、パスワード、プロファイル データ、ロール、要求、トークン、電子メールの確認などを管理します。

ユーザーは、Identity に格納されているログイン情報を使用してアカウントを作成することができます。あるいは、外部ログイン プロバイダーを使用できます。 サポートされている外部ログイン プロバイダーには、Facebook、Google、Microsoft アカウント、Twitter があります。

すべてのユーザーの認証をグローバルに要求する方法の詳細については、「認証されたユーザーを要求する」を参照してください。

Identity ソース コードは GitHub で入手できます。 Identity をスキャフォールディングし、生成されたファイルを表示してテンプレートと Identity とのやりとりを確認します。

Identity は通常、ユーザー名、パスワード、およびプロファイル データを格納するために SQL Server データベースを使用して構成されます。 別の固定ストア (たとえば、Azure Table Storage) を使用することもできます。

このトピックでは、Identity を使用して、ユーザーの登録、ログイン、およびログアウトを行う方法について学習します。 注: テンプレートでは、ユーザーのユーザー名と電子メールを同じものとして扱います。 Identity を使用するアプリの作成に関する詳細な手順については、「次の手順」を参照してください。

Microsoft identity プラットフォーム は

  • Azure Active Directory (Azure AD) 開発者プラットフォームが進化したものです。
  • ASP.NET Core アプリでの認証と認可のための代替 identity ソリューションです。
  • ASP.NET Core Identity とは関係ありません。

ASP.NET Core Identity では、ASP.NET Core Web アプリにユーザー インターフェイス (UI) ログイン機能が追加されます。 Web API と SPA をセキュリティで保護するには、次のいずれかを使用します。

Duende IdentityServer は、ASP.NET Core 用の OpenID Connect および OAuth 2.0 フレームワークです。 Duende IdentityServer により、次のセキュリティ機能が有効になります。

  • サービスとしての認証 (AaaS)
  • 複数のアプリケーションの種類でのシングル サインオン/オフ (SSO)
  • API のアクセス制御
  • Federation Gateway

詳細については、「Duende IdentityServer の概要」をご覧ください。

その他の認証プロバイダーについて詳しくは、「ASP.NET Core のコミュニティ OSS 認証オプション」を参照してください

サンプル コードを表示またはダウンロードします (ダウンロード方法)。

認証を使用して Web アプリを作成する

個々のユーザー アカウントを使用して、ASP.NET Core Web アプリケーション プロジェクトを作成します。

  • [File]>[New]>[Project] の順に選択します。
  • [ASP.NET Core Web アプリケーション] を選択します。 プロジェクトに WebApp1 という名前を付け、プロジェクトのダウンロードと同じ名前空間を使用します。 [OK] をクリックします。
  • ASP.NET Core Web アプリケーションを選んでから、[認証の変更] を選択します。
  • [個々のユーザー アカウント] を選択し、[OK] をクリックします。

生成されたプロジェクトによって、ASP.NET CoreIdentityRazor クラス ライブラリとして提供されます。 IdentityRazor クラス ライブラリにより、Identity 領域でエンドポイントが公開されます。 次に例を示します。

  • /Identity/Account/Login
  • /Identity/Account/Logout
  • /Identity/Account/Manage

移行を適用する

移行を適用してデータベースを初期化します。

パッケージ マネージャー コンソール (PMC) で次のコマンドを実行します。

PM> Update-Database

登録とログインをテストする

アプリを実行し、ユーザーを登録します。 ご利用の画面のサイズによっては、ナビゲーション トグル ボタンを選択して [登録] および [ログイン] リンクを表示する必要がある場合があります。

Identity データベースを表示する

  • [表示] メニューから [SQL Server オブジェクト エクスプローラー] (SSOX) を選択します。
  • (localdb)MSSQLLocalDB(SQL Server 13) に移動します。 dbo.AspNetUsers>View Data を右クリックします。

SQL Server オブジェクト エクスプローラーの AspNetUsers テーブルのコンテキスト メニュー

Identity サービスを構成する

サービスは ConfigureServices に追加されます。 一般的なパターンは、すべての Add{Service} メソッドを呼び出した後、すべての services.Configure{Service} メソッドを呼び出すことです。

public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
     // options.UseSqlite(
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));
    services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();
    services.AddRazorPages();

    services.Configure<IdentityOptions>(options =>
    {
        // Password settings.
        options.Password.RequireDigit = true;
        options.Password.RequireLowercase = true;
        options.Password.RequireNonAlphanumeric = true;
        options.Password.RequireUppercase = true;
        options.Password.RequiredLength = 6;
        options.Password.RequiredUniqueChars = 1;

        // Lockout settings.
        options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
        options.Lockout.MaxFailedAccessAttempts = 5;
        options.Lockout.AllowedForNewUsers = true;

        // User settings.
        options.User.AllowedUserNameCharacters =
        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
        options.User.RequireUniqueEmail = false;
    });

    services.ConfigureApplicationCookie(options =>
    {
        // Cookie settings
        options.Cookie.HttpOnly = true;
        options.ExpireTimeSpan = TimeSpan.FromMinutes(5);

        options.LoginPath = "/Identity/Account/Login";
        options.AccessDeniedPath = "/Identity/Account/AccessDenied";
        options.SlidingExpiration = true;
    });
}

上の強調表示されているコードでは、既定のオプション値で Identity を構成します。 サービスは、依存性の挿入を介してアプリで使用できるようになります。

Identity は、UseAuthentication を呼び出すことによって有効になります。 UseAuthentication では、要求パイプラインに認証ミドルウェアを追加します。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseDatabaseErrorPage();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

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

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}
public void ConfigureServices(IServiceCollection services)
{
    services.AddDbContext<ApplicationDbContext>(options =>
        // options.UseSqlite(
        options.UseSqlServer(
            Configuration.GetConnectionString("DefaultConnection")));
    services.AddDatabaseDeveloperPageExceptionFilter();
    services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();
    services.AddRazorPages();

    services.Configure<IdentityOptions>(options =>
    {
        // Password settings.
        options.Password.RequireDigit = true;
        options.Password.RequireLowercase = true;
        options.Password.RequireNonAlphanumeric = true;
        options.Password.RequireUppercase = true;
        options.Password.RequiredLength = 6;
        options.Password.RequiredUniqueChars = 1;

        // Lockout settings.
        options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
        options.Lockout.MaxFailedAccessAttempts = 5;
        options.Lockout.AllowedForNewUsers = true;

        // User settings.
        options.User.AllowedUserNameCharacters =
        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+";
        options.User.RequireUniqueEmail = false;
    });

    services.ConfigureApplicationCookie(options =>
    {
        // Cookie settings
        options.Cookie.HttpOnly = true;
        options.ExpireTimeSpan = TimeSpan.FromMinutes(5);

        options.LoginPath = "/Identity/Account/Login";
        options.AccessDeniedPath = "/Identity/Account/AccessDenied";
        options.SlidingExpiration = true;
    });
}

前のコードでは、既定のオプション値で Identity を構成します。 サービスは、依存性の挿入を介してアプリで使用できるようになります。

Identity は、UseAuthentication を呼び出すことによって有効になります。 UseAuthentication では、要求パイプラインに認証ミドルウェアを追加します。

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    if (env.IsDevelopment())
    {
        app.UseDeveloperExceptionPage();
        app.UseMigrationsEndPoint();
    }
    else
    {
        app.UseExceptionHandler("/Error");
        app.UseHsts();
    }

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

    app.UseRouting();

    app.UseAuthentication();
    app.UseAuthorization();

    app.UseEndpoints(endpoints =>
    {
        endpoints.MapRazorPages();
    });
}

テンプレートで生成されたアプリでは、承認は使用されません。 app.UseAuthorization は、アプリで承認が追加された場合に確実に正しい順序で追加されるようにするために含まれています。 UseRoutingUseAuthenticationUseAuthorization、および UseEndpoints は、前のコードに示されている順序で呼び出す必要があります。

IdentityOptionsStartup の詳細については、「IdentityOptions」およびアプリケーションの起動に関するページを参照してください。

Register、Login、LogOut、および RegisterConfirmation をスキャフォールディングする

RegisterLoginLogOut、および RegisterConfirmation ファイルを追加します。 「承認を使用して Razor プロジェクトに identity をスキャフォールディングする 」の手順に従って、このセクションに示されているコードを生成します。

登録を確認する

ユーザーが Register ページの [登録] ボタンをクリックすると、RegisterModel.OnPostAsync アクションが呼び出されます。 ユーザーは、_userManager オブジェクトで CreateAsync(TUser) によって作成されます。

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");
    ExternalLogins = (await _signInManager.GetExternalAuthenticationSchemesAsync())
                                          .ToList();
    if (ModelState.IsValid)
    {
        var user = new IdentityUser { UserName = Input.Email, Email = Input.Email };
        var result = await _userManager.CreateAsync(user, Input.Password);
        if (result.Succeeded)
        {
            _logger.LogInformation("User created a new account with password.");

            var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
            code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
            var callbackUrl = Url.Page(
                "/Account/ConfirmEmail",
                pageHandler: null,
                values: new { area = "Identity", userId = user.Id, code = code },
                protocol: Request.Scheme);

            await _emailSender.SendEmailAsync(Input.Email, "Confirm your email",
                $"Please confirm your account by <a href='{HtmlEncoder.Default.Encode(callbackUrl)}'>clicking here</a>.");

            if (_userManager.Options.SignIn.RequireConfirmedAccount)
            {
                return RedirectToPage("RegisterConfirmation", 
                                      new { email = Input.Email });
            }
            else
            {
                await _signInManager.SignInAsync(user, isPersistent: false);
                return LocalRedirect(returnUrl);
            }
        }
        foreach (var error in result.Errors)
        {
            ModelState.AddModelError(string.Empty, error.Description);
        }
    }

    // If we got this far, something failed, redisplay form
    return Page();
}

既定のアカウント検証を無効にする

既定のテンプレートでは、ユーザーは Account.RegisterConfirmation にリダイレクトされ、アカウントを確認するリンクを選択できます。 既定値 Account.RegisterConfirmation は、テスト目的で "のみ" 使用されます。運用アプリでは、自動アカウント検証を無効にしてください。

確認済みのアカウントを必須にして、登録時に即時ログインできないようにするには、/Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.csDisplayConfirmAccountLink = false を設定します。

[AllowAnonymous]
public class RegisterConfirmationModel : PageModel
{
    private readonly UserManager<IdentityUser> _userManager;
    private readonly IEmailSender _sender;

    public RegisterConfirmationModel(UserManager<IdentityUser> userManager, IEmailSender sender)
    {
        _userManager = userManager;
        _sender = sender;
    }

    public string Email { get; set; }

    public bool DisplayConfirmAccountLink { get; set; }

    public string EmailConfirmationUrl { get; set; }

    public async Task<IActionResult> OnGetAsync(string email, string returnUrl = null)
    {
        if (email == null)
        {
            return RedirectToPage("/Index");
        }

        var user = await _userManager.FindByEmailAsync(email);
        if (user == null)
        {
            return NotFound($"Unable to load user with email '{email}'.");
        }

        Email = email;
        // Once you add a real email sender, you should remove this code that lets you confirm the account
        DisplayConfirmAccountLink = false;
        if (DisplayConfirmAccountLink)
        {
            var userId = await _userManager.GetUserIdAsync(user);
            var code = await _userManager.GenerateEmailConfirmationTokenAsync(user);
            code = WebEncoders.Base64UrlEncode(Encoding.UTF8.GetBytes(code));
            EmailConfirmationUrl = Url.Page(
                "/Account/ConfirmEmail",
                pageHandler: null,
                values: new { area = "Identity", userId = userId, code = code, returnUrl = returnUrl },
                protocol: Request.Scheme);
        }

        return Page();
    }
}

ログイン

ログイン フォームは次の場合に表示されます。

  • [ログイン] リンクが選択されている。
  • ユーザーが、アクセスを承認されていない、またはシステムによって認証されていない場合に、制限付きページにアクセスしようとした。

[ログイン] ページのフォームが送信されると、OnPostAsync アクションが呼び出されます。 PasswordSignInAsync_signInManager オブジェクトで呼び出されます。

public async Task<IActionResult> OnPostAsync(string returnUrl = null)
{
    returnUrl = returnUrl ?? Url.Content("~/");

    if (ModelState.IsValid)
    {
        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, 
        // set lockoutOnFailure: true
        var result = await _signInManager.PasswordSignInAsync(Input.Email,
                           Input.Password, Input.RememberMe, lockoutOnFailure: true);
        if (result.Succeeded)
        {
            _logger.LogInformation("User logged in.");
            return LocalRedirect(returnUrl);
        }
        if (result.RequiresTwoFactor)
        {
            return RedirectToPage("./LoginWith2fa", new
            {
                ReturnUrl = returnUrl,
                RememberMe = Input.RememberMe
            });
        }
        if (result.IsLockedOut)
        {
            _logger.LogWarning("User account locked out.");
            return RedirectToPage("./Lockout");
        }
        else
        {
            ModelState.AddModelError(string.Empty, "Invalid login attempt.");
            return Page();
        }
    }

    // If we got this far, something failed, redisplay form
    return Page();
}

承認の決定を行う方法に関する詳細については、「ASP.NET Core での認可の概要」を参照してください。

ログアウト

[ログアウト] リンクによって LogoutModel.OnPost アクションが呼び出されます。

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;
using System.Threading.Tasks;

namespace WebApp1.Areas.Identity.Pages.Account
{
    [AllowAnonymous]
    public class LogoutModel : PageModel
    {
        private readonly SignInManager<IdentityUser> _signInManager;
        private readonly ILogger<LogoutModel> _logger;

        public LogoutModel(SignInManager<IdentityUser> signInManager, ILogger<LogoutModel> logger)
        {
            _signInManager = signInManager;
            _logger = logger;
        }

        public void OnGet()
        {
        }

        public async Task<IActionResult> OnPost(string returnUrl = null)
        {
            await _signInManager.SignOutAsync();
            _logger.LogInformation("User logged out.");
            if (returnUrl != null)
            {
                return LocalRedirect(returnUrl);
            }
            else
            {
                return RedirectToPage();
            }
        }
    }
}

前のコードでは、ブラウザーで新しい要求が実行され、ユーザーの identity が更新されるように、コード return RedirectToPage(); をリダイレクトする必要があります。

SignOutAsync により、cookie に格納されているユーザーのクレームがクリアされます。

post は、Pages/Shared/_LoginPartial.cshtml で指定されます。

@using Microsoft.AspNetCore.Identity
@inject SignInManager<IdentityUser> SignInManager
@inject UserManager<IdentityUser> UserManager

<ul class="navbar-nav">
@if (SignInManager.IsSignedIn(User))
{
    <li class="nav-item">
        <a  class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index" 
                                              title="Manage">Hello @User.Identity.Name!</a>
    </li>
    <li class="nav-item">
        <form class="form-inline" asp-area="Identity" asp-page="/Account/Logout" 
                                  asp-route-returnUrl="@Url.Page("/", new { area = "" })" 
                                  method="post" >
            <button  type="submit" class="nav-link btn btn-link text-dark">Logout</button>
        </form>
    </li>
}
else
{
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Register">Register</a>
    </li>
    <li class="nav-item">
        <a class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Login">Login</a>
    </li>
}
</ul>

Identity をテストする

既定の Web プロジェクト テンプレートでは、home ページへの匿名アクセスが許可されます。 Identity をテストするには、[Authorize] を追加します。

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.Extensions.Logging;

namespace WebApp1.Pages
{
    [Authorize]
    public class PrivacyModel : PageModel
    {
        private readonly ILogger<PrivacyModel> _logger;

        public PrivacyModel(ILogger<PrivacyModel> logger)
        {
            _logger = logger;
        }

        public void OnGet()
        {
        }
    }
}

サインインしている場合は、サインアウトします。アプリを実行し、Privacy リンクを選択します。 ログイン ページにリダイレクトされます。

Identity を調べる

Identity をさらに詳しく調べるには、次のようにします。

Identity のコンポーネント

Identity に依存するすべての NuGet パッケージは、ASP.NET Core 共有フレームワークに含まれています。

Identity のプライマリ パッケージは Microsoft.AspNetCore.Identity です。 このパッケージには、ASP.NET Core Identity 用のインターフェイスのコア セットが含まれており、Microsoft.AspNetCore.Identity.EntityFrameworkCore によって含められます。

ASP.NET Core Identity への移行

既存の Identity ストアの移行に関する詳細とガイダンスについては、認証と Identity の移行に関するページを参照してください。

パスワードの強度の設定

パスワードの最小要件を設定するサンプルについては、「構成」を参照してください。

静的 Identity アセットを発行しないようにする

静的 Identity アセット (Identity UI 用のスタイルシートと JavaScript ファイル) が Web ルートに発行されるのを防ぐには、次の ResolveStaticWebAssetsInputsDependsOn プロパティと RemoveIdentityAssets ターゲットをアプリのプロジェクト ファイルに追加します。

<PropertyGroup>
  <ResolveStaticWebAssetsInputsDependsOn>RemoveIdentityAssets</ResolveStaticWebAssetsInputsDependsOn>
</PropertyGroup>

<Target Name="RemoveIdentityAssets">
  <ItemGroup>
    <StaticWebAsset Remove="@(StaticWebAsset)" Condition="%(SourceId) == 'Microsoft.AspNetCore.Identity.UI'" />
  </ItemGroup>
</Target>

次の手順