Buat mekanisme login menggunakan otentikasi cookie, dan buat mekanisme untuk dialihkan jika Anda tidak diautentikasi

Halaman Diperbarui :
Tanggal pembuatan halaman :

Lingkungan operasi

Visual Studio
  • Komunitas Visual Studio 2022
ASP.NET Core (MVC, Halaman Pisau Cukur)
6.0

Pada awalnya

Kali ini, ASP.NET Core akan menggunakan otentikasi cookie sebagai mekanisme otentikasi login. Anda dapat menganggap otentikasi cookie mirip dengan otentikasi bentuk tradisional.

Mekanisme otentikasi lain untuk ASP.NET Core adalah ASP.NET Core Identity. Selain autentikasi menggunakan formulir, ini memungkinkan Anda untuk mengautentikasi dengan API, menggunakan layanan login eksternal, mengelola dan mengatur ulang kata sandi, dll. Anda dapat menggunakan banyak fitur. Namun, dari sudut pandang hanya membuat layar login sederhana kali ini, itu akan menjadi mekanisme otentikasi yang agak berlebihan. Kami tidak akan menggunakannya kali ini.

Dalam tips otentikasi cookie yang diperkenalkan kali ini, Anda tidak dapat menampilkan apa pun selain layar login kecuali Anda masuk. Jika Anda mencoba menavigasi ke layar lain, Anda akan diarahkan ke layar login. Jika Anda masuk, Anda dapat melihat layar lain.

Untuk saat ini, Anda dapat masuk dengan memasukkan nama pengguna dan kata sandi Anda di layar masuk. Otentikasi pengguna itu sendiri diimplementasikan sebagai tempat sementara. Dalam hal ini, fokus utamanya adalah pada penerapan otentikasi cookie, sehingga esensi dari proses penentuan seperti apakah kata sandi sudah benar bukanlah esensinya.

Tip ini hanya menjelaskan sebagian dari program. Untuk kode lengkap, unduh program lengkap. Ini juga mencakup kerangka kerja MVC dan Razor Pages.

Membuat proyek

Mulai Visual Studio dan buat proyek baru.

Untuk Razor Pages, pilih ASP.NET Core Web App, atau untuk MVC, pilih ASP.NET Core Web App (Model-View-Controller).

Tentukan nama proyek pilihan Anda dan lokasi untuk proyek tersebut.

Untuk jenis otentikasi, pilih "Tidak Ada". Jika Anda memilih autentikasi lain, Anda akan menggunakan ASP.NET Core Identity. Ketika Anda selesai dengan pengaturan, klik tombol "Buat".

Setelah membuat proyek, layar yang ditunjukkan di bawah ini akan ditampilkan saat debugging dijalankan. Kami akan membuat program berdasarkan layar ini.

Edit Program.cs (Razor Pages, MVC Common)

Tambahkan definisi yang diperlukan untuk otentikasi cookie ke Program.cs. Ruang nama yang akan ditambahkan adalah sebagai berikut:

using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;

Berikut kode builder.Services untuk ditambahkan ke .

// === 省略 ===

// 「Razor Pages」のコード
// builder.Services.AddRazorPages();
// 「MVC」のコード
// builder.Services.AddControllersWithViews();

// ※ここから追加

// Cookie による認証スキームを追加する
builder.Services
  .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
  .AddCookie();

builder.Services.AddAuthorization(options =>
{
  // AllowAnonymous 属性が指定されていないすべての画面、アクションなどに対してユーザー認証が必要となる
  options.FallbackPolicy = new AuthorizationPolicyBuilder()
    .RequireAuthenticatedUser()
    .Build();
});

// ※ここまで追加

var app = builder.Build();

// === 省略 ===

AddAuthenticationAddCookie Anda dapat mengaktifkan otentikasi cookie dengan menjalankan metode dan. Jika Anda tidak perlu mengubah nama skema, CookieAuthenticationDefaults.AuthenticationScheme tentukan .

AddAuthorization Jika Anda options.FallbackPolicy RequireAuthenticatedUser menentukan untuk metode ini Anda dapat menerapkan kebijakan yang diperlukan autentikasi ke semua halaman, semua pengontrol, dan tindakan. Jika Anda ingin meminta otentikasi untuk apa pun selain layar login, ini adalah metode yang berguna dalam hal mengurangi kode dan mencegah kesalahan dalam deskripsi. Anda harus menulis kode yang tidak memerlukan otentikasi untuk layar login secara terpisah.

Berikut ini adalah app kode untuk .

// === 省略 ===

app.UseRouting();

app.UseAuthentication(); // [追加] 認証
app.UseAuthorization(); // 認可

// 「Razor Pages」のコード
// app.MapRazorPages();
// 「MVC」のコード
// app.MapControllerRoute(
//     name: "default",
//     pattern: "{controller=Home}/{action=Index}/{id?}");

// === 省略 ===

Karena kita ingin menambahkan fungsionalitas otentikasi ke aplikasi, app.UseAuthentication() kita akan menambahkan file . Deskripsi lokasi sesuai dengan dokumentasi MSDN, aplikasi. UseAuthorization(). Selain itu, ini masih template.

Program untuk proyek Razor Pages

Membuat halaman login (Pages/Account/Login.cshtml.cs)

Membuat file

Buat halaman login. Jalur file harus dibuat sebagai "/Pages/Account/Login.cshtml". Ini karena jalur login default seperti itu. Jika Anda ingin mengubah jalur ini, Anda Program.cs dapat melakukannya dengan mengatur argumen metode AddCookie .

Anda dapat membuatnya dengan menyalin file lain alih-alih membuatnya dari menu, tetapi dalam hal ini, harap perbaiki program dengan benar.

Izinkan pengguna mengakses halaman login tanpa login

Program.cs Karena semua halaman hanya dapat diakses ketika Anda masuk, Anda hanya perlu mengatur halaman masuk sehingga Anda dapat mengaksesnya bahkan jika Anda tidak masuk.

AllowAnonymous Dengan menambahkan atribut, halaman target dapat diakses meskipun tidak diautentikasi. AllowAnonymous Atribut dapat digunakan di tempat lain selain layar login, seperti operasi API yang tidak terkait dengan autentikasi cookie.

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Security.Claims;

namespace AspNetCoreCookieAuthenticationRazorPages.Pages.Account
{
  [AllowAnonymous]
  public class LoginModel : PageModel
  {
  }
}

Membuat variabel untuk menerima input

Ketika Anda masuk, Anda menyatakan nama pengguna Anda untuk dapat menerima nilai-nilai tersebut karena Anda memasukkan kata sandi Anda.

// 省略

[AllowAnonymous]
public class LoginModel : PageModel
{
  /// <summary>ユーザー名。</summary>
  [BindProperty]
  [Required]
  [DisplayName("ユーザー名")]
  public string UserName { get; set; } = "";

  /// <summary>パスワード。</summary>
  [BindProperty]
  [Required]
  [DataType(DataType.Password)]
  [DisplayName("パスワード")]
  public string Password { get; set; } = "";
}

Tentukan nama pengguna dan kata sandi untuk autentikasi masuk

Awalnya, itu akan disimpan dalam database, dll., Tetapi karena penilaian pengguna bukan fokus utama kali ini, saya akan menjadikannya sebagai tempat sementara.

// 省略

[AllowAnonymous]
public class LoginModel : PageModel
{
  // 省略

  /// <summary>仮のユーザーデータベースとする。</summary>
  private Dictionary<string, string> UserAccounts { get; set; } = new Dictionary<string, string>
    {
      { "user1", "password1" },
      { "user2", "password2" },
    };
}

Proses login

/// <summary>ログイン処理。</summary>
public async Task<ActionResult> OnPost()
{
  // 入力内容にエラーがある場合は処理を中断してエラー表示
  if (ModelState.IsValid == false) return Page();

  // ユーザーの存在チェックとパスワードチェック (仮実装)
  // 本 Tips は Cookie 認証ができるかどうかの確認であるため入力内容やパスワードの厳密なチェックは行っていません
  if (UserAccounts.TryGetValue(UserName, out string? getPass) == false || Password != getPass)
  {
    ModelState.AddModelError("", "ユーザー名またはパスワードが一致しません。");
    return Page();
  }

  // サインインに必要なプリンシパルを作る
  var claims = new[] { new Claim(ClaimTypes.Name, UserName) };
  var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
  var principal = new ClaimsPrincipal(identity);

  // 認証クッキーをレスポンスに追加
  await HttpContext.SignInAsync(principal);

  // ログインが必要な画面にリダイレクトします
  return RedirectToPage("/Index");
}

Ini adalah proses otentikasi setelah menekan tombol login. Jika nama pengguna dan kata sandi cocok, autentikasi dimungkinkan.

Kode yang dijelaskan adalah kode minimum yang diperlukan untuk autentikasi,ClaimClaimsIdentityClaimsPrincipal dan HttpContext.SignInAsync Dengan memanggil metode, cookie dihasilkan dan diautentikasi.

Jika klaim tambahan diperlukan atau kedaluwarsa cookie diperlukan, parameter tambahan ditambahkan.

Setelah masuk, Anda akan diarahkan ke , di mana /Index otentikasi diperlukan.

Proses logout

/// <summary>ログアウト処理。</summary>
public async Task OnGetLogout()
{
  // 認証クッキーをレスポンスから削除
  await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
}

Logout Ketika diakses dengan handler, diproses untuk log out. HttpContext.SignOutAsync Dengan memanggil metode ini, Anda dapat menghapus cookie dan mengembalikannya ke keadaan di mana Anda tidak masuk.

Membuat Tampilan

Kami tidak memperhitungkan penampilan. Tambahkan bidang untuk memasukkan nama pengguna dan kata sandi Anda seperti yang ditunjukkan di bawah ini, dan tempatkan tombol untuk masuk. Anda juga harus memiliki tautan ke akses tanpa masuk untuk /Index pengujian.

Karena sulit untuk memasukkan nama pengguna dan kata sandi, nilai awal ditetapkan.

@page
@model AspNetCoreCookieAuthenticationRazorPages.Pages.Account.LoginModel
@{}

<form asp-action="Login">
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    </div>
  </div>

  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <label asp-for="UserName" class="form-label"></label>
      <input asp-for="UserName" class="form-control" value="user1" />
      <span asp-validation-for="UserName" class="text-danger"></span>
    </div>
  </div>
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <label asp-for="Password" class="form-label"></label>
      <input asp-for="Password" class="form-control" value="password1" />
      <span asp-validation-for="Password" class="text-danger"></span>
    </div>
  </div>
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <button type="submit" class="btn btn-primary">ログイン</button>
    </div>
  </div>
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <a asp-page="/Index">認証が必要な画面へ直接リンク</a>
    </div>
  </div>
</form>

@section Scripts {
  @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}

Membuat tautan keluar (/Pages/Shared/_Layout.cshtml)

Kami tidak akan membuat perubahan apa pun pada layar beranda, tetapi kami akan menempatkan tautan keluar di bilah navigasi. Juga, untuk pengujian, posting tautan yang membawa Anda ke layar masuk tanpa keluar.

<!-- 中略 -->
<div class="navbar-collapse collapse d-sm-inline-flex justify-content-between">
  <ul class="navbar-nav flex-grow-1">
    <li class="nav-item">
      <a class="nav-link text-dark" asp-area="" asp-page="/Index">Home</a>
    </li>
    <li class="nav-item">
      <a class="nav-link text-dark" asp-area="" asp-page="/Privacy">Privacy</a>
    </li>
    <!-- ここから追加 -->
    <li class="nav-item">
      <a class="nav-link text-dark" asp-page="/Account/Login" asp-page-handler="Logout">ログアウト</a>
    </li>
    <li class="nav-item">
      <a class="nav-link text-dark" asp-page="/Account/Login">ログアウトせずログインへ</a>
    </li>
    <!-- ここまで追加 -->
  </ul>
</div>
<!-- 中略 -->

Itu saja untuk kode Razor Pages.

Program untuk Proyek MVC

Membuat Model Login

Anda telah membuat model untuk menerima nilai yang dimasukkan pada layar login.

namespace AspNetCoreCookieAuthenticationMvc.Models
{
  public class LoginModel
  {
    /// <summary>ユーザー名。</summary>
    [Required]
    [DisplayName("ユーザー名")]
    public string UserName { get; set; } = "";

    /// <summary>パスワード。</summary>
    [Required]
    [DataType(DataType.Password)]
    [DisplayName("パスワード")]
    public string Password { get; set; } = "";
  }
}

Membuat AccountController

Buat pengontrol dan tindakan yang diperlukan untuk membuat layar login. Buat nama AccountController pengontrol sebagai . Ini karena secara default, nama pengontrol dan nama tindakan pada layar login diatur ke "~/Account/Login". Jika Anda ingin mengubah jalur ini, Anda dapat melakukannya dalam opsi AddCookie metode di Program.cs. Untuk saat ini, kami akan melanjutkan dengan pengaturan default.

Pertama, mari kita buat sisi Controller.

using AspNetCoreCookieAuthenticationMvc.Models;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;

namespace AspNetCoreCookieAuthenticationMvc.Controllers
{
  /// <remarks>
  /// <see cref="AllowAnonymous"/> 属性は Cookie 認証していなくてもアクセスできる Action (Controller) であることを示す。
  /// </remarks>
  [AllowAnonymous]
  public class AccountController : Controller
  {
  }
}

AllowAnonymous Dengan memberikan atribut, semua tindakan di dalamnya dapat dilakukan tanpa diautentikasi. Ini memungkinkan Anda untuk mengakses hanya layar login tanpa otentikasi.

AllowAnonymous Atribut juga dapat digunakan dalam pengontrol khusus API yang tidak terkait dengan otentikasi cookie di tempat lain selain layar login.

Selanjutnya, tentukan pengguna dan kata sandi yang dapat masuk. Awalnya, itu akan disimpan dalam database, dll., Tetapi karena penilaian pengguna bukan fokus utama kali ini, saya akan menjadikannya sebagai tempat sementara.

[AllowAnonymous]
public class AccountController : Controller
{
  /// <summary>仮のユーザーデータベースとする。</summary>
  private Dictionary<string, string> UserAccounts { get; set; } = new Dictionary<string, string>
    {
      { "user1", "password1" },
      { "user2", "password2" },
    };
}

Berikut ini adalah tindakan yang menampilkan layar login. Karena hanya ditampilkan, ia mengembalikan tampilan apa adanya.

/// <summary>ログイン画面を表示します。</summary>
public IActionResult Login() => View();

Di bawah ini adalah kode yang akan diproses saat masuk.

/// <summary>ログイン処理を実行します。</summary>
[HttpPost]
public async Task<IActionResult> Login(LoginModel model)
{
  // 入力内容にエラーがある場合は処理を中断してエラー表示
  if (ModelState.IsValid == false) return View(model);

  // ユーザーの存在チェックとパスワードチェック (仮実装)
  // 本 Tips は Cookie 認証ができるかどうかの確認であるため入力内容やパスワードの厳密なチェックは行っていません
  if (UserAccounts.TryGetValue(model.UserName, out string? getPass) == false || model.Password != getPass)
  {
    ModelState.AddModelError("", "ユーザー名またはパスワードが一致しません。");
    return View(model);
  }

  // サインインに必要なプリンシパルを作る
  var claims = new[] { new Claim(ClaimTypes.Name, model.UserName) };
  var identity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
  var principal = new ClaimsPrincipal(identity);

  // 認証クッキーをレスポンスに追加
  await HttpContext.SignInAsync(principal);

  // ログインが必要な画面にリダイレクトします
  return RedirectToAction(nameof(HomeController.Index), "Home");
}

Ini adalah proses otentikasi setelah menekan tombol login. Jika nama pengguna dan kata sandi cocok, autentikasi dimungkinkan.

Kode yang dijelaskan adalah kode minimum yang diperlukan untuk autentikasi,ClaimClaimsIdentityClaimsPrincipal dan HttpContext.SignInAsync Dengan memanggil metode, cookie dihasilkan dan diautentikasi.

Jika klaim tambahan diperlukan atau kedaluwarsa cookie diperlukan, parameter tambahan ditambahkan.

Setelah masuk, Anda akan diarahkan ke , di mana ~/Home/Index otentikasi diperlukan.

Akhirnya, proses logout ditambahkan.

/// <summary>ログアウト処理を実行します。</summary>
public async Task<IActionResult> Logout()
{
  // 認証クッキーをレスポンスから削除
  await HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);

  // ログイン画面にリダイレクト
  return RedirectToAction(nameof(Login));
}

HttpContext.SignOutAsync Dengan memanggil metode ini, Anda dapat menghapus cookie dan mengembalikannya ke keadaan di mana Anda tidak masuk.

Membuat tampilan (formulir login) (/Views/Account/Login.cshtml)

Login Klik kanan tindakan untuk menambahkan tampilan. Anda juga dapat membuatnya dengan menyalinnya dari file lain.

Kami tidak memperhitungkan penampilan. Tambahkan bidang untuk memasukkan nama pengguna dan kata sandi Anda seperti yang ditunjukkan di bawah ini, dan tempatkan tombol untuk masuk. Anda juga harus memiliki tautan ke akses tanpa masuk untuk Home/Index pengujian.

Karena sulit untuk memasukkan nama pengguna dan kata sandi, nilai awal ditetapkan.

@model LoginModel
@{}

<form asp-action="Login">
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <div asp-validation-summary="ModelOnly" class="text-danger"></div>
    </div>
  </div>

  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <label asp-for="UserName" class="form-label"></label>
      <input asp-for="UserName" class="form-control" value="user1" />
      <span asp-validation-for="UserName" class="text-danger"></span>
    </div>
  </div>
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <label asp-for="Password" class="form-label"></label>
      <input asp-for="Password" class="form-control" value="password1" />
      <span asp-validation-for="Password" class="text-danger"></span>
    </div>
  </div>
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <button type="submit" class="btn btn-primary">ログイン</button>
    </div>
  </div>
  <div class="row m-1 g-3">
    <div class="col-sm-6 offset-sm-3">
      <a asp-controller="Home" asp-action="Index">認証が必要な画面へ直接リンク</a>
    </div>
  </div>
</form>

@section Scripts {
  @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}

Membuat tautan keluar (/Views/Shared/_Layout.cshtml)

Kami tidak akan membuat perubahan apa pun pada layar beranda, tetapi kami akan menempatkan tautan keluar di bilah navigasi. Juga, untuk pengujian, posting tautan yang membawa Anda ke layar masuk tanpa keluar.

<!-- 中略 -->
<div class="navbar-collapse collapse d-sm-inline-flex flex-sm-row-reverse">
  <ul class="navbar-nav flex-grow-1">
    <li class="nav-item">
      <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Index">Home</a>
    </li>
    <li class="nav-item">
      <a class="nav-link text-dark" asp-area="" asp-controller="Home" asp-action="Privacy">Privacy</a>
    </li>
    <!-- ここから追加 -->
    <li class="nav-item">
      <a class="nav-link text-dark" asp-controller="Account" asp-action="Logout">ログアウト</a>
    </li>
    <li class="nav-item">
      <a class="nav-link text-dark" asp-controller="Account" asp-action="Login">ログアウトせずログインへ</a>
    </li>
    <!-- ここまで追加 -->
  </ul>
</div>
<!-- 中略 -->

Itu saja untuk kode MVC.

Konfirmasi operasi

Ini melengkapi penerapan autentikasi cookie minimum yang diperlukan. Coba jalankan dan lihat cara kerjanya. Perilaku harus berubah tergantung pada apakah Anda login atau tidak. Sebagai contoh sederhana, Anda dapat melihat perilaku berikut.

Operasi hasil operasi
Pulang tanpa login Redirect ke layar login
Login Membuka layar beranda
Keluar dari rumah dan pulang tanpa masuk Redirect ke layar login
Pulang tanpa keluar dari rumah dan masuk Membuka layar beranda