Utwórz mechanizm logowania za pomocą uwierzytelniania plików cookie i stwórz mechanizm, który będzie przekierowywany, jeśli nie jesteś uwierzytelniony

Strona zaktualizowana :
Data utworzenia strony :

Środowisko pracy

Visual Studio
  • Społeczność programu Visual Studio 2022
ASP.NET Core (MVC, Razor Pages)
6.0

Na początku

Tym razem ASP.NET Core wykorzysta uwierzytelnianie plików cookie jako mechanizm uwierzytelniania logowania. Możesz myśleć o uwierzytelnianiu plików cookie jako o podobnym do uwierzytelniania za pomocą tradycyjnych formularzy.

Innym mechanizmem uwierzytelniania dla ASP.NET Core jest ASP.NET Core Identity. Oprócz uwierzytelniania za pomocą formularzy umożliwia to uwierzytelnianie za pomocą interfejsów API, korzystanie z zewnętrznych usług logowania, zarządzanie i resetowanie haseł itp. Możesz korzystać z wielu funkcji. Jednak z punktu widzenia stworzenia prostego ekranu logowania tym razem będzie to nieco przesadzony mechanizm uwierzytelniania. Tym razem go nie użyjemy.

W wprowadzonych tym razem wskazówkach dotyczących uwierzytelniania plików cookie nie możesz wyświetlić niczego poza ekranem logowania, chyba że się zalogujesz. Jeśli spróbujesz przejść do innego ekranu, zostaniesz przekierowany do ekranu logowania. Jeśli się zalogujesz, możesz wyświetlić inne ekrany.

Na razie możesz się zalogować, wpisując swoją nazwę użytkownika i hasło na ekranie logowania. Samo uwierzytelnianie użytkownika jest realizowane jako miejsce tymczasowe. W tym przypadku główny nacisk kładziony jest na wdrożenie uwierzytelniania plików cookie, więc istota procesu ustalania, taka jak poprawność hasła, nie jest istotą.

Ta wskazówka opisuje tylko część programu. Aby uzyskać pełny kod, pobierz kompletny program. Obejmuje również struktury MVC i Razor Pages.

Tworzenie projektu

Uruchom program Visual Studio i utwórz nowy projekt.

W przypadku Razor Pages wybierz pozycję ASP.NET Podstawowa aplikacja internetowa lub MVC wybierz pozycję ASP.NET Podstawowa aplikacja internetowa (Model-View-Controller).

Określ wybraną nazwę projektu i lokalizację projektu.

Jako typ uwierzytelniania wybierz "Brak". Jeśli wybierzesz inne uwierzytelnianie, użyjesz tożsamości ASP.NET podstawowej. Po zakończeniu ustawień kliknij przycisk "Utwórz".

Po utworzeniu projektu podczas debugowania zostanie wyświetlony poniższy ekran. Na podstawie tego ekranu stworzymy program.

Edytowanie pliku Program.cs (Razor Pages, MVC Common)

Dodaj definicje wymagane do uwierzytelniania plików cookie do pliku Program.cs. Przestrzenie nazw, które należy dodać, są następujące:

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

builder.Services Oto kod, który należy dodać do pliku .

// === 省略 ===

// 「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 Uwierzytelnianie plików cookie można włączyć, wykonując metodę and. Jeśli nie ma potrzeby zmiany nazwy schematu, CookieAuthenticationDefaults.AuthenticationScheme określ .

AddAuthorization Jeśli określisz options.FallbackPolicy RequireAuthenticatedUser dla metody Zasady wymagane uwierzytelniania można zastosować do wszystkich stron, wszystkich kontrolerów i akcji. Jeśli chcesz wymagać uwierzytelnienia dla czegokolwiek innego niż ekran logowania, jest to przydatna metoda pod względem zmniejszenia kodu i zapobiegania błędom w opisie. Będziesz musiał napisać kod, który nie wymaga uwierzytelniania dla ekranu logowania osobno.

Poniżej znajduje app się kod pliku .

// === 省略 ===

app.UseRouting();

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

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

// === 省略 ===

Ponieważ chcemy dodać funkcjonalność uwierzytelniania do aplikacji, app.UseAuthentication() dodamy . Lokalizacja opisu jest zgodna z dokumentacją MSDN, aplikacja. UseAuthorization(). Poza tym nadal jest to szablon.

Programy dla projektów Razor Pages

Tworzenie strony logowania (Pages/Account/Login.cshtml.cs)

Tworzenie pliku

Utwórz stronę logowania. Ścieżka pliku powinna zostać utworzona jako "/Pages/Account/Login.cshtml". Dzieje się tak, ponieważ domyślna ścieżka logowania jest taka. Jeśli chcesz zmienić tę ścieżkę, możesz Program.cs to zrobić, ustawiając argument AddCookie metody .

Możesz go utworzyć, kopiując inne pliki zamiast tworzyć go z menu, ale w takim przypadku napraw program poprawnie.

Zezwalaj użytkownikom na dostęp do strony logowania bez logowania

Program.cs Ponieważ dostęp do wszystkich stron można uzyskać tylko wtedy, gdy jesteś zalogowany, musisz ustawić tylko stronę logowania, aby mieć do niej dostęp, nawet jeśli nie jesteś zalogowany.

AllowAnonymous Dodając atrybuty, można uzyskać dostęp do strony docelowej, nawet jeśli nie jest ona uwierzytelniona. AllowAnonymous Atrybuty mogą być używane w innych miejscach niż ekran logowania, takich jak operacje API niezwiązane z uwierzytelnianiem plików 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
  {
  }
}

Tworzenie zmiennej do odbierania danych wejściowych

Logując się, deklarujesz swoją nazwę użytkownika, aby móc otrzymywać te wartości, ponieważ wprowadzasz hasło.

// 省略

[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; } = "";
}

Zdefiniuj nazwę użytkownika i hasło do uwierzytelniania logowania

Pierwotnie miał być przechowywany w bazie danych itp., ale ponieważ tym razem nie skupia się na ocenie użytkownika, zrobię to jako miejsce tymczasowe.

// 省略

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

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

Proces logowania

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

Jest to proces uwierzytelniania po naciśnięciu przycisku logowania. Jeśli nazwa użytkownika i hasło są zgodne, uwierzytelnianie jest możliwe.

Opisany kod jest minimalnym kodem wymaganym do uwierzytelnienia,ClaimClaimsIdentityClaimsPrincipal a HttpContext.SignInAsync Wywołanie metody powoduje wygenerowanie i uwierzytelnienie pliku cookie.

Jeśli wymagane są dodatkowe oświadczenia lub wymagane jest wygaśnięcie pliku cookie, dodawane są dodatkowe parametry.

Po zalogowaniu zostaniesz przekierowany do , gdzie /Index wymagane jest uwierzytelnienie.

Proces wylogowania

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

Logout W przypadku uzyskiwania dostępu za pomocą programu obsługi jest on przetwarzany w celu wylogowania. HttpContext.SignOutAsync Wywołując metodę, możesz usunąć plik cookie i przywrócić go do stanu, w którym nie jesteś zalogowany.

Tworzenie widoku

Nie bierzemy pod uwagę wyglądu. Dodaj pola do wpisania nazwy użytkownika i hasła, jak pokazano poniżej, i umieść przycisk, aby się zalogować. Powinieneś również mieć link do dostępu bez logowania się w celu /Index przetestowania.

Ponieważ wprowadzanie nazwy użytkownika i hasła jest kłopotliwe, ustawiana jest wartość początkowa.

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

Utwórz link wylogowania (/Pages/Shared/_Layout.cshtml)

Nie wprowadzimy żadnych zmian na ekranie głównym, ale umieścimy link do wylogowania na pasku nawigacyjnym. Ponadto, w celu przetestowania, opublikuj link, który przeniesie Cię do ekranu logowania bez wylogowywania.

<!-- 中略 -->
<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>
<!-- 中略 -->

To tyle, jeśli chodzi o kod Razor Pages.

Programy dla projektów MVC

Tworzenie modelu logowania

Utworzono model, który będzie odbierał wartości wprowadzone na ekranie logowania.

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; } = "";
  }
}

Tworzenie kontrolera konta

Utwórz kontrolery i akcje wymagane do utworzenia ekranu logowania. Utwórz nazwę AccountController kontrolera jako . Dzieje się tak, ponieważ domyślnie nazwa kontrolera i nazwa akcji na ekranie logowania są ustawione na "~/Account/Login". Jeśli chcesz zmienić tę ścieżkę, możesz to zrobić w opcjach AddCookie metody w pliku Program.cs. Na razie przejdziemy do ustawień domyślnych.

Najpierw utwórzmy stronę kontrolera.

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 Przyznając atrybut, wszystkie czynności w nim zawarte mogą być wykonywane bez uwierzytelniania. Umożliwia to dostęp tylko do ekranu logowania bez uwierzytelniania.

AllowAnonymous Atrybuty mogą być również używane w kontrolerach tylko API, które nie są związane z uwierzytelnianiem plików cookie w innych miejscach niż ekran logowania.

Następnie zdefiniuj użytkowników i hasła, które mogą się logować. Pierwotnie miał być przechowywany w bazie danych itp., ale ponieważ tym razem nie skupia się na ocenie użytkownika, zrobię to jako miejsce tymczasowe.

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

Poniżej znajduje się akcja, która wyświetla ekran logowania. Ponieważ jest tylko wyświetlany, zwraca widok w takiej postaci, w jakiej jest.

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

Poniżej znajduje się kod, który należy przetworzyć podczas logowania.

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

Jest to proces uwierzytelniania po naciśnięciu przycisku logowania. Jeśli nazwa użytkownika i hasło są zgodne, uwierzytelnianie jest możliwe.

Opisany kod jest minimalnym kodem wymaganym do uwierzytelnienia,ClaimClaimsIdentityClaimsPrincipal a HttpContext.SignInAsync Wywołanie metody powoduje wygenerowanie i uwierzytelnienie pliku cookie.

Jeśli wymagane są dodatkowe oświadczenia lub wymagane jest wygaśnięcie pliku cookie, dodawane są dodatkowe parametry.

Po zalogowaniu zostaniesz przekierowany do , gdzie ~/Home/Index wymagane jest uwierzytelnienie.

Na koniec dodawany jest proces wylogowania.

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

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

HttpContext.SignOutAsync Wywołując metodę, możesz usunąć plik cookie i przywrócić go do stanu, w którym nie jesteś zalogowany.

Tworzenie widoku (formularz logowania) (/Views/Account/Login.cshtml)

Login Kliknij prawym przyciskiem myszy akcję, aby dodać widok. Możesz go również utworzyć, kopiując go z innego pliku.

Nie bierzemy pod uwagę wyglądu. Dodaj pola do wpisania nazwy użytkownika i hasła, jak pokazano poniżej, i umieść przycisk, aby się zalogować. Powinieneś również mieć link do dostępu bez logowania się w celu Home/Index przetestowania.

Ponieważ wprowadzanie nazwy użytkownika i hasła jest kłopotliwe, ustawiana jest wartość początkowa.

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

Utwórz link wylogowania (/Views/Shared/_Layout.cshtml)

Nie wprowadzimy żadnych zmian na ekranie głównym, ale umieścimy link do wylogowania na pasku nawigacyjnym. Ponadto, w celu przetestowania, opublikuj link, który przeniesie Cię do ekranu logowania bez wylogowywania.

<!-- 中略 -->
<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>
<!-- 中略 -->

To tyle, jeśli chodzi o kod MVC.

Potwierdzenie działania

Na tym kończy się minimalna wymagana implementacja uwierzytelniania plików cookie. Spróbuj go uruchomić i zobacz, jak to działa. Zachowanie powinno się zmieniać w zależności od tego, czy jesteś zalogowany, czy nie. Jako prosty przykład możesz zobaczyć następujące zachowanie.

Operacja wynik działania
Idź do domu bez logowania Przekieruj do ekranu logowania
login Przejdź do ekranu głównego
Wyloguj się ze strony głównej i wróć do domu bez logowania Przekieruj do ekranu logowania
Idź do domu bez wylogowywania się z domu i logowania Przejdź do ekranu głównego