Maak een inlogmechanisme aan met behulp van cookie-authenticatie en maak een mechanisme dat wordt omgeleid als u niet bent geverifieerd

Pagina bijgewerkt :
Aanmaakdatum van pagina :

Werkomgeving

Visual Studio
  • Visual Studio-community 2022
ASP.NET Core (MVC, Razor Pages)
6.0

Eerst

Deze keer zal ASP.NET Core cookie-authenticatie gebruiken als authenticatiemechanisme voor inloggen. U kunt cookie-authenticatie zien als vergelijkbaar met traditionele formulierauthenticatie.

Een ander authenticatiemechanisme voor ASP.NET Core is ASP.NET Core Identity. Naast authenticatie met behulp van formulieren, kunt u zich hiermee authenticeren met API's, externe inlogservices gebruiken, wachtwoorden beheren en resetten, enz. U kunt veel functies gebruiken. Vanuit het oogpunt van het maken van een eenvoudig inlogscherm zal het deze keer echter een ietwat overdreven authenticatiemechanisme zijn. We zullen het deze keer niet gebruiken.

In de cookie-authenticatietips die deze keer zijn geïntroduceerd, kunt u niets anders weergeven dan het inlogscherm, tenzij u inlogt. Als u naar een ander scherm probeert te navigeren, wordt u doorgestuurd naar het inlogscherm. Als je inlogt, kun je andere schermen bekijken.

Voorlopig kunt u inloggen door uw gebruikersnaam en wachtwoord in te voeren op het inlogscherm. De gebruikersauthenticatie zelf wordt geïmplementeerd als een tijdelijke plaats. In dit geval ligt de focus vooral op de implementatie van cookie-authenticatie, dus de essentie van het vaststellingsproces, zoals of het wachtwoord correct is, is niet de essentie.

Deze tip beschrijft slechts een deel van het programma. Download voor de volledige code het volledige programma. Het omvat ook zowel MVC- als Razor Pages-frameworks.

Een project maken

Start Visual Studio en maak een nieuw project.

Selecteer voor Razor Pages ASP.NET Core Web App of voor MVC ASP.NET Core Web App (Model-View-Controller).

Geef een projectnaam naar keuze en een locatie voor het project op.

Selecteer voor het verificatietype "Geen". Kies je voor een andere authenticatie, dan gebruik je ASP.NET Core Identity. Als u klaar bent met de instellingen, klikt u op de knop "Maken".

Na het aanmaken van het project wordt het onderstaande scherm weergegeven wanneer foutopsporing wordt uitgevoerd. Op basis van dit scherm maken we een programma.

Programma bewerken.cs (Razor Pages, MVC Common)

Voeg de definities die nodig zijn voor cookie-authenticatie toe aan Program.cs. De toe te voegen naamruimten zijn als volgt:

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

Hier is de code die u builder.Services moet toevoegen aan .

// === 省略 ===

// 「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 U kunt cookie-authenticatie inschakelen door de methode en uit te voeren. Als u de naam van het schema niet hoeft te wijzigen, CookieAuthenticationDefaults.AuthenticationScheme geeft u .

AddAuthorization Als u options.FallbackPolicy RequireAuthenticatedUser opgeeft voor de methode U kunt een beleid voor verificatie toepassen op alle pagina's, alle controllers en acties. Als u authenticatie wilt vereisen voor iets anders dan het inlogscherm, is dit een handige methode om de code te verminderen en fouten in de beschrijving te voorkomen. U moet code schrijven waarvoor geen authenticatie vereist is voor het inlogscherm afzonderlijk.

Het volgende is app de code voor .

// === 省略 ===

app.UseRouting();

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

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

// === 省略 ===

Omdat we authenticatiefunctionaliteit aan de applicatie willen toevoegen, app.UseAuthentication() zullen we . De beschrijvingslocatie is volgens de MSDN-documentatie, app. UseAuthorization(). Verder is het nog steeds een sjabloon.

Programma's voor Razor Pages-projecten

Een aanmeldingspagina maken (Pages/Account/Login.cshtml.cs)

Een bestand maken

Maak een inlogpagina aan. Het bestandspad moet worden gemaakt als "/Pages/Account/Login.cshtml". Dit komt omdat het standaard inlogpad zo is. Als u dit pad wilt wijzigen, kunt u Program.cs dit doen door het argument van de methode van .AddCookie

U kunt het maken door andere bestanden te kopiëren in plaats van het vanuit het menu te maken, maar in dat geval moet u het programma correct repareren.

Gebruikers toegang geven tot de inlogpagina zonder in te loggen

Program.cs Aangezien alle pagina's alleen toegankelijk zijn als u bent ingelogd, hoeft u alleen de inlogpagina zo in te stellen dat u er ook toegang toe hebt als u niet bent ingelogd.

AllowAnonymous Door attributen toe te voegen, kan de doelpagina worden geopend, zelfs als deze niet is geverifieerd. AllowAnonymous Attributen kunnen op andere plaatsen dan het inlogscherm worden gebruikt, zoals API-bewerkingen die geen verband houden met cookieverificatie.

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
  {
  }
}

Een variabele maken om invoer te ontvangen

Wanneer u inlogt, geeft u uw gebruikersnaam aan om die waarden te kunnen ontvangen omdat u uw wachtwoord invoert.

// 省略

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

Definieer een gebruikersnaam en wachtwoord voor aanmeldingsverificatie

Oorspronkelijk zou het worden opgeslagen in een database, enz., maar aangezien het oordeel van de gebruiker deze keer niet de belangrijkste focus is, zal ik er een tijdelijke plek van maken.

// 省略

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

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

Inloggen proces

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

Dit is het authenticatieproces na het indrukken van de inlogknop. Als de gebruikersnaam en het wachtwoord overeenkomen, is authenticatie mogelijk.

De beschreven code is de minimumcode die vereist is voor authenticatie,ClaimClaimsIdentityClaimsPrincipal en HttpContext.SignInAsync Door de methode aan te roepen, wordt een cookie gegenereerd en geauthenticeerd.

Als er aanvullende claims nodig zijn of als het verlopen van cookies vereist is, worden aanvullende parameters toegevoegd.

Nadat u bent ingelogd, wordt u doorgestuurd naar , waar /Index authenticatie vereist is.

Uitlogproces

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

Logout Wanneer het wordt benaderd met een handler, wordt het verwerkt om uit te loggen. HttpContext.SignOutAsync Door de methode aan te roepen, kunt u de cookie verwijderen en terugzetten naar een staat waarin u niet bent ingelogd.

Een weergave maken

We houden geen rekening met het uiterlijk. Voeg velden toe voor het invoeren van uw gebruikersnaam en wachtwoord zoals hieronder weergegeven, en plaats een knop om in te loggen. Je moet ook een link hebben om toegang te krijgen zonder in te loggen om te /Index testen.

Omdat het lastig is om de gebruikersnaam en het wachtwoord in te voeren, wordt de beginwaarde ingesteld.

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

Een afmeldlink maken (/Pages/Shared/_Layout.cshtml)

We brengen geen wijzigingen aan in het startscherm, maar we plaatsen wel een uitloglink in de navigatiebalk. Plaats ook voor het testen een link die u naar het inlogscherm brengt zonder uit te loggen.

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

Dat is het voor de Razor Pages-code.

Programma's voor MVC-projecten

Een inlogmodel maken

U hebt een model gemaakt om de waarden te ontvangen die op het inlogscherm zijn ingevoerd.

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

Een AccountController aanmaken

Maak de controllers en acties die nodig zijn om het inlogscherm te maken. Maak de naam AccountController van de controller als . Dit komt omdat de controllernaam en actienaam op het inlogscherm standaard zijn ingesteld op "~/Account/Login". Als u dit pad wilt wijzigen, kunt u dit doen in de opties van AddCookie de methode in Programma.cs. Voorlopig gaan we verder met de standaardinstellingen.

Laten we eerst de controllerkant maken.

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 Door het attribuut toe te kennen, kunnen alle acties erin worden uitgevoerd zonder te worden geverifieerd. Hierdoor heeft u alleen toegang tot het inlogscherm zonder authenticatie.

AllowAnonymous Attributen kunnen ook worden gebruikt in API-only controllers die niet gerelateerd zijn aan cookie-authenticatie op andere plaatsen dan het inlogscherm.

Definieer vervolgens de gebruikers en wachtwoorden waarmee kan worden ingelogd. Oorspronkelijk zou het worden opgeslagen in een database, enz., maar aangezien het oordeel van de gebruiker deze keer niet de belangrijkste focus is, zal ik er een tijdelijke plek van maken.

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

Het volgende is een actie die het inlogscherm weergeeft. Omdat het alleen wordt weergegeven, wordt de weergave geretourneerd zoals deze is.

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

Hieronder vindt u de code die moet worden verwerkt bij het inloggen.

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

Dit is het authenticatieproces na het indrukken van de inlogknop. Als de gebruikersnaam en het wachtwoord overeenkomen, is authenticatie mogelijk.

De beschreven code is de minimumcode die vereist is voor authenticatie,ClaimClaimsIdentityClaimsPrincipal en HttpContext.SignInAsync Door de methode aan te roepen, wordt een cookie gegenereerd en geauthenticeerd.

Als er aanvullende claims nodig zijn of als het verlopen van cookies vereist is, worden aanvullende parameters toegevoegd.

Nadat u bent ingelogd, wordt u doorgestuurd naar , waar ~/Home/Index authenticatie vereist is.

Ten slotte wordt het uitlogproces toegevoegd.

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

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

HttpContext.SignOutAsync Door de methode aan te roepen, kunt u de cookie verwijderen en terugzetten naar een staat waarin u niet bent ingelogd.

Een weergave maken (aanmeldingsformulier) (/Views/Account/Login.cshtml)

Login Klik met de rechtermuisknop op de actie om een weergave toe te voegen. U kunt het ook maken door het uit een ander bestand te kopiëren.

We houden geen rekening met het uiterlijk. Voeg velden toe voor het invoeren van uw gebruikersnaam en wachtwoord zoals hieronder weergegeven, en plaats een knop om in te loggen. Je moet ook een link hebben om toegang te krijgen zonder in te loggen om te Home/Index testen.

Omdat het lastig is om de gebruikersnaam en het wachtwoord in te voeren, wordt de beginwaarde ingesteld.

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

Een afmeldlink maken (/Views/Shared/_Layout.cshtml)

We brengen geen wijzigingen aan in het startscherm, maar we plaatsen wel een uitloglink in de navigatiebalk. Plaats ook voor het testen een link die u naar het inlogscherm brengt zonder uit te loggen.

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

Dat is het voor de MVC-code.

Bevestiging van de werking

Hiermee is de minimaal vereiste implementatie van cookie-authenticatie voltooid. Probeer het uit te voeren en kijk hoe het werkt. Het gedrag zou moeten veranderen, afhankelijk van of u bent ingelogd of niet. Als eenvoudig voorbeeld kunt u het volgende gedrag zien.

Operatie bedrijfsresultaat
Ga naar huis zonder in te loggen Doorverwijzen naar inlogscherm
inloggen Ga naar het startscherm
Log uit bij huis en ga naar huis zonder in te loggen Doorverwijzen naar inlogscherm
Ga naar huis zonder uit te loggen en in te loggen Ga naar het startscherm