Pengantar Identity ASP.NET Core

Oleh Rick Anderson

ASP.NET Core Identity:

  • Adalah API yang mendukung fungsionalitas login antarmuka pengguna (UI).
  • Mengelola pengguna, kata sandi, data profil, peran, klaim, token, konfirmasi email, dan banyak lagi.

Pengguna dapat membuat akun dengan informasi masuk yang disimpan di atau Identity mereka dapat menggunakan penyedia login eksternal. Penyedia login eksternal yang didukung termasuk Facebook, Google, Akun Microsoft, dan Twitter.

Untuk informasi tentang cara mengharuskan semua pengguna diautentikasi secara global, lihat Memerlukan pengguna yang diautentikasi.

Kode Identity sumber tersedia di GitHub. Perancah Identity dan lihat file yang dihasilkan untuk meninjau interaksi templat dengan Identity.

Identity biasanya dikonfigurasi menggunakan database SQL Server untuk menyimpan nama pengguna, kata sandi, dan data profil. Atau, penyimpanan persisten lain dapat digunakan, misalnya, Azure Table Storage.

Dalam topik ini, Anda mempelajari cara menggunakan Identity untuk mendaftar, masuk, dan keluar dari pengguna. Catatan: templat memperlakukan nama pengguna dan email sebagai sama untuk pengguna. Untuk instruksi selengkapnya tentang membuat aplikasi yang menggunakan Identity, lihat Langkah Berikutnya.

ASP.NET Core Identity tidak terkait dengan platform identitas Microsoft. platform identitas Microsoft adalah:

  • Evolusi platform pengembang Azure Active Directory (Azure AD).
  • Solusi identitas alternatif untuk autentikasi dan otorisasi di aplikasi ASP.NET Core.

ASP.NET Core Identity menambahkan fungsionalitas masuk antarmuka pengguna (UI) ke aplikasi web ASP.NET Core. Untuk mengamankan API web dan SPAs, gunakan salah satu hal berikut ini:

Duende Identity Server adalah Koneksi OpenID dan kerangka kerja OAuth 2.0 untuk ASP.NET Core. Duende Identity Server memungkinkan fitur keamanan berikut:

  • Autentikasi sebagai Layanan (AaaS)
  • Akses menyeluruh (SSO) melalui beberapa jenis aplikasi
  • Kontrol akses untuk API
  • Gateway Federasi

Penting

Perangkat Lunak Duende mungkin mengharuskan Anda membayar biaya lisensi untuk penggunaan produksi Server Identity Duende. Untuk informasi lebih lanjut, lihat Bermigrasi dari ASP.NET Core 5.0 ke 6.0.

Untuk informasi selengkapnya, lihat dokumentasi Duende Identity Server (situs web Duende Software).

Lihat atau unduh kode sampel (cara mengunduh).

Membuat aplikasi Web dengan autentikasi

Buat proyek ASP.NET Core Web Application dengan Akun Pengguna Individual.

  • Pilih template Aplikasi Web ASP.NET Core. Beri nama proyek WebApp1 agar memiliki namespace yang sama dengan unduhan proyek. Klik OK.
  • Pada input Jenis autentikasi, pilih Akun Pengguna Individual.

Proyek yang dihasilkan menyediakan ASP.NET Core Identity sebagai Razor Pustaka Kelas. IdentityRazor Pustaka Kelas mengekspos titik akhir dengan Identity area . Contohnya:

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

Menerapkan migrasi

Terapkan migrasi untuk menginisialisasi database.

Jalankan perintah berikut di Package Manager Console (PMC):

Update-Database

Uji Daftar dan Masuk

Jalankan aplikasi dan daftarkan pengguna. Bergantung pada ukuran layar, Anda mungkin perlu memilih tombol alih navigasi untuk melihat tautan Daftar dan Masuk .

Identity Menampilkan database

  • Dari menu Tampilan , pilih SQL Server Object Explorer (SSOX).
  • Navigasi ke (localdb)MSSQLLocalDB(SQL Server 13). Klik kanan pada dbo. Data Tampilan AspNetUsers>:

Contextual menu on AspNetUsers table in SQL Server Object Explorer

Mengonfigurasi Identity layanan

Layanan ditambahkan dalam Program.cs. Pola umumnya adalah memanggil metode dalam urutan berikut:

  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();

Kode sebelumnya dikonfigurasi Identity dengan nilai opsi default. Layanan tersedia untuk aplikasi melalui injeksi dependensi.

Identity diaktifkan dengan memanggil UseAuthentication. UseAuthenticationmenambahkan middleware autentikasi ke alur permintaan.

Aplikasi yang dihasilkan templat tidak menggunakan otorisasi. app.UseAuthorization disertakan untuk memastikannya ditambahkan dalam urutan yang benar jika aplikasi menambahkan otorisasi. UseRouting, UseAuthentication, dan UseAuthorization harus dipanggil dalam urutan yang ditunjukkan dalam kode sebelumnya.

Untuk informasi selengkapnya tentang IdentityOptions, lihat IdentityOptions dan Startup Aplikasi.

Scaffold Register, Login, LogOut, dan RegisterConfirmation

RegisterTambahkan file , Login, LogOut, dan RegisterConfirmation . Ikuti identitas Perancah ke dalam Razor proyek dengan instruksi otorisasi untuk menghasilkan kode yang ditunjukkan di bagian ini.

Periksa Daftar

Saat pengguna mengklik tombol Daftar di Register halaman, RegisterModel.OnPostAsync tindakan akan dipanggil. Pengguna dibuat oleh CreateAsync(TUser) pada _userManager objek:

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();
}

Menonaktifkan verifikasi akun default

Dengan templat default, pengguna dialihkan ke Account.RegisterConfirmation tempat mereka dapat memilih tautan untuk mengonfirmasi akun. Default Account.RegisterConfirmation hanya digunakan untuk pengujian, verifikasi akun otomatis harus dinonaktifkan di aplikasi produksi.

Untuk memerlukan akun yang dikonfirmasi dan mencegah masuk segera saat pendaftaran, atur DisplayConfirmAccountLink = false di /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs:

[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();
    }
}

Masuk

Formulir Masuk ditampilkan saat:

  • Tautan Masuk dipilih.
  • Pengguna mencoba mengakses halaman terbatas yang tidak diizinkan untuk diakses atau saat belum diautentikasi oleh sistem.

Ketika formulir di halaman Masuk dikirimkan, OnPostAsync tindakan dipanggil. PasswordSignInAsync dipanggil pada _signInManager objek .

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();
}

Untuk informasi tentang cara membuat keputusan otorisasi, lihat Pengantar otorisasi di ASP.NET Core.

Keluar

Tautan Keluar memanggil LogoutModel.OnPost tindakan.

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();
            }
        }
    }
}

Dalam kode sebelumnya, kode return RedirectToPage(); harus menjadi pengalihan sehingga browser melakukan permintaan baru dan identitas untuk pengguna diperbarui.

SignOutAsync menghapus klaim pengguna yang disimpan dalam cookie.

Postingan ditentukan dalam 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>

Tes Identity

Templat proyek web default memungkinkan akses anonim ke halaman beranda. Untuk menguji Identity, tambahkan [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()
        {
        }
    }
}

Jika Anda masuk, keluar. Jalankan aplikasi dan pilih Privacy tautan. Anda diarahkan ke halaman masuk.

Menjelajahi Identity

Untuk menjelajahi Identity secara lebih rinci:

Identity Komponen

IdentitySemua paket NuGet -dependen disertakan dalam kerangka kerja bersama ASP.NET Core.

Paket utama untuk Identity adalah Microsoft.AspNetCore.Identity. Paket ini berisi serangkaian antarmuka inti untuk ASP.NET Core Identity, dan disertakan oleh Microsoft.AspNetCore.Identity.EntityFrameworkCore.

Bermigrasi ke ASP.NET Core Identity

Untuk informasi dan panduan selengkapnya tentang memigrasikan Identity penyimpanan yang ada, lihat Memigrasikan Autentikasi dan Identity.

Mengatur kekuatan kata sandi

Lihat Konfigurasi untuk sampel yang menetapkan persyaratan kata sandi minimum.

TambahkanDefaultIdentity dan TambahkanIdentity

AddDefaultIdentity diperkenalkan di ASP.NET Core 2.1. AddDefaultIdentity Panggilan mirip dengan memanggil yang berikut ini:

Lihat Menambahkan sumberDefaultIdentity untuk informasi selengkapnya.

Mencegah penerbitan aset statis Identity

Untuk mencegah penerbitan aset statis Identity (lembar gaya dan file JavaScript untuk Identity UI) ke akar web, tambahkan properti dan RemoveIdentityAssets target berikut ResolveStaticWebAssetsInputsDependsOn ke file proyek aplikasi:

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

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

Langkah berikutnya

Oleh Rick Anderson

ASP.NET Core Identity:

  • Adalah API yang mendukung fungsionalitas login antarmuka pengguna (UI).
  • Mengelola pengguna, kata sandi, data profil, peran, klaim, token, konfirmasi email, dan banyak lagi.

Pengguna dapat membuat akun dengan informasi masuk yang disimpan di atau Identity mereka dapat menggunakan penyedia login eksternal. Penyedia login eksternal yang didukung termasuk Facebook, Google, Akun Microsoft, dan Twitter.

Untuk informasi tentang cara mengharuskan semua pengguna diautentikasi secara global, lihat Memerlukan pengguna yang diautentikasi.

Kode Identity sumber tersedia di GitHub. Perancah Identity dan lihat file yang dihasilkan untuk meninjau interaksi templat dengan Identity.

Identity biasanya dikonfigurasi menggunakan database SQL Server untuk menyimpan nama pengguna, kata sandi, dan data profil. Atau, penyimpanan persisten lain dapat digunakan, misalnya, Azure Table Storage.

Dalam topik ini, Anda mempelajari cara menggunakan Identity untuk mendaftar, masuk, dan keluar dari pengguna. Catatan: templat memperlakukan nama pengguna dan email sebagai sama untuk pengguna. Untuk instruksi selengkapnya tentang membuat aplikasi yang menggunakan Identity, lihat Langkah Berikutnya.

platform identitas Microsoft adalah:

  • Evolusi platform pengembang Azure Active Directory (Azure AD).
  • Solusi identitas alternatif untuk autentikasi dan otorisasi di aplikasi ASP.NET Core.
  • Tidak terkait dengan ASP.NET Core Identity.

ASP.NET Core Identity menambahkan fungsionalitas masuk antarmuka pengguna (UI) ke aplikasi web ASP.NET Core. Untuk mengamankan API web dan SPAs, gunakan salah satu hal berikut ini:

Duende IdentityServer adalah Koneksi OpenID dan kerangka kerja OAuth 2.0 untuk ASP.NET Core. Duende IdentityServer memungkinkan fitur keamanan berikut:

  • Autentikasi sebagai Layanan (AaaS)
  • Akses menyeluruh (SSO) melalui beberapa jenis aplikasi
  • Kontrol akses untuk API
  • Gateway Federasi

Untuk informasi selengkapnya, lihat Gambaran Umum Duende IdentityServer.

Untuk informasi selengkapnya tentang penyedia autentikasi lainnya, lihat Opsi autentikasi OSS Komunitas untuk ASP.NET Core

Lihat atau unduh kode sampel (cara mengunduh).

Membuat aplikasi Web dengan autentikasi

Buat proyek ASP.NET Core Web Application dengan Akun Pengguna Individual.

  • Pilih File>Baru>Proyek.
  • Pilih ASP.NET Core Web Application. Beri nama proyek WebApp1 agar memiliki namespace yang sama dengan unduhan proyek. Klik OK.
  • Pilih ASP.NET Core Web Application, lalu pilih Ubah Autentikasi.
  • Pilih Akun Pengguna Individual dan klik OK.

Proyek yang dihasilkan menyediakan ASP.NET Core Identity sebagai Razor Pustaka Kelas. IdentityRazor Pustaka Kelas mengekspos titik akhir dengan Identity area . Contohnya:

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

Menerapkan migrasi

Terapkan migrasi untuk menginisialisasi database.

Jalankan perintah berikut di Package Manager Console (PMC):

PM> Update-Database

Uji Daftar dan Masuk

Jalankan aplikasi dan daftarkan pengguna. Bergantung pada ukuran layar, Anda mungkin perlu memilih tombol alih navigasi untuk melihat tautan Daftar dan Masuk .

Identity Menampilkan database

  • Dari menu Tampilan , pilih SQL Server Object Explorer (SSOX).
  • Navigasi ke (localdb)MSSQLLocalDB(SQL Server 13). Klik kanan pada dbo. Data Tampilan AspNetUsers>:

Contextual menu on AspNetUsers table in SQL Server Object Explorer

Mengonfigurasi Identity layanan

Layanan ditambahkan dalam ConfigureServices. Pola umumnya adalah memanggil semua Add{Service} metode, lalu memanggil semua services.Configure{Service} metode.

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;
    });
}

Kode yang disorot Identity sebelumnya dikonfigurasi dengan nilai opsi default. Layanan tersedia untuk aplikasi melalui injeksi dependensi.

Identity diaktifkan dengan memanggil UseAuthentication. UseAuthenticationmenambahkan middleware autentikasi ke alur permintaan.

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;
    });
}

Kode sebelumnya dikonfigurasi Identity dengan nilai opsi default. Layanan tersedia untuk aplikasi melalui injeksi dependensi.

Identity diaktifkan dengan memanggil UseAuthentication. UseAuthenticationmenambahkan middleware autentikasi ke alur permintaan.

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();
    });
}

Aplikasi yang dihasilkan templat tidak menggunakan otorisasi. app.UseAuthorization disertakan untuk memastikannya ditambahkan dalam urutan yang benar jika aplikasi menambahkan otorisasi. UseRouting, , UseAuthenticationUseAuthorization, dan UseEndpoints harus dipanggil dalam urutan yang ditunjukkan dalam kode sebelumnya.

Untuk informasi selengkapnya tentang IdentityOptions dan Startup, lihat IdentityOptions dan Startup Aplikasi.

Scaffold Register, Login, LogOut, dan RegisterConfirmation

RegisterTambahkan file , Login, LogOut, dan RegisterConfirmation . Ikuti identitas Perancah ke dalam Razor proyek dengan instruksi otorisasi untuk menghasilkan kode yang ditunjukkan di bagian ini.

Periksa Daftar

Saat pengguna mengklik tombol Daftar di Register halaman, RegisterModel.OnPostAsync tindakan akan dipanggil. Pengguna dibuat oleh CreateAsync(TUser) pada _userManager objek:

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();
}

Menonaktifkan verifikasi akun default

Dengan templat default, pengguna dialihkan ke Account.RegisterConfirmation tempat mereka dapat memilih tautan untuk mengonfirmasi akun. Default Account.RegisterConfirmation hanya digunakan untuk pengujian, verifikasi akun otomatis harus dinonaktifkan di aplikasi produksi.

Untuk memerlukan akun yang dikonfirmasi dan mencegah masuk segera saat pendaftaran, atur DisplayConfirmAccountLink = false di /Areas/Identity/Pages/Account/RegisterConfirmation.cshtml.cs:

[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();
    }
}

Masuk

Formulir Masuk ditampilkan saat:

  • Tautan Masuk dipilih.
  • Pengguna mencoba mengakses halaman terbatas yang tidak diizinkan untuk diakses atau saat belum diautentikasi oleh sistem.

Ketika formulir di halaman Masuk dikirimkan, OnPostAsync tindakan dipanggil. PasswordSignInAsync dipanggil pada _signInManager objek .

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();
}

Untuk informasi tentang cara membuat keputusan otorisasi, lihat Pengantar otorisasi di ASP.NET Core.

Keluar

Tautan Keluar memanggil LogoutModel.OnPost tindakan.

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();
            }
        }
    }
}

Dalam kode sebelumnya, kode return RedirectToPage(); harus menjadi pengalihan sehingga browser melakukan permintaan baru dan identitas untuk pengguna diperbarui.

SignOutAsync menghapus klaim pengguna yang disimpan dalam cookie.

Postingan ditentukan dalam 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>

Tes Identity

Templat proyek web default memungkinkan akses anonim ke halaman beranda. Untuk menguji Identity, tambahkan [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()
        {
        }
    }
}

Jika Anda masuk, keluar. Jalankan aplikasi dan pilih Privacy tautan. Anda diarahkan ke halaman masuk.

Menjelajahi Identity

Untuk menjelajahi Identity secara lebih rinci:

Identity Komponen

IdentitySemua paket NuGet -dependen disertakan dalam kerangka kerja bersama ASP.NET Core.

Paket utama untuk Identity adalah Microsoft.AspNetCore.Identity. Paket ini berisi serangkaian antarmuka inti untuk ASP.NET Core Identity, dan disertakan oleh Microsoft.AspNetCore.Identity.EntityFrameworkCore.

Bermigrasi ke ASP.NET Core Identity

Untuk informasi dan panduan selengkapnya tentang memigrasikan Identity penyimpanan yang ada, lihat Memigrasikan Autentikasi dan Identity.

Mengatur kekuatan kata sandi

Lihat Konfigurasi untuk sampel yang menetapkan persyaratan kata sandi minimum.

Mencegah penerbitan aset statis Identity

Untuk mencegah penerbitan aset statis Identity (lembar gaya dan file JavaScript untuk Identity UI) ke akar web, tambahkan properti dan RemoveIdentityAssets target berikut ResolveStaticWebAssetsInputsDependsOn ke file proyek aplikasi:

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

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

Langkah berikutnya