Skapa en inloggningsmekanism med hjälp av cookie-autentisering och skapa en mekanism som ska omdirigeras om du inte är autentiserad

Sidan uppdaterad :
Datum för skapande av sida :

Omvärld

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

Först

Den här gången kommer ASP.NET Core att använda cookie-autentisering som en mekanism för inloggningsautentisering. Du kan tänka på cookie-autentisering som liknar traditionell formulärautentisering.

En annan autentiseringsmekanism för ASP.NET Core är ASP.NET Core Identity. Förutom autentisering med hjälp av formulär kan du autentisera med API:er, använda externa inloggningstjänster, hantera och återställa lösenord etc. Du kan använda många funktioner. Men ur synvinkeln att bara skapa en enkel inloggningsskärm den här gången kommer det att vara en något överdriven autentiseringsmekanism. Vi kommer inte att använda den den här gången.

I de tips för autentisering av cookies som introducerades den här gången kan du inte visa något annat än inloggningsskärmen om du inte loggar in. Om du försöker navigera till en annan skärm kommer du att omdirigeras till inloggningsskärmen. Om du loggar in kan du se andra skärmar.

Tills vidare kan du logga in genom att ange ditt användarnamn och lösenord på inloggningsskärmen. Själva användarautentiseringen implementeras som en tillfällig plats. I det här fallet ligger huvudfokus på implementeringen av cookie-autentisering, så kärnan i bestämningsprocessen, till exempel om lösenordet är korrekt, är inte kärnan.

Det här tipset beskriver bara en del av programmet. För den fullständiga koden, ladda ner hela programmet. Den täcker också både MVC- och Razor Pages-ramverk.

Skapa ett projekt

Starta Visual Studio och skapa ett nytt projekt.

För Razor Pages väljer du ASP.NET Core Web App eller för MVC väljer du ASP.NET Core Web App (Model-View-Controller).

Ange ett valfritt projektnamn och en plats för projektet.

Som autentiseringstyp väljer du "Ingen". Om du väljer annan autentisering använder du ASP.NET Core Identity. När du är klar med inställningarna klickar du på knappen "Skapa".

När du har skapat projektet visas skärmen nedan när felsökning utförs. Vi kommer att skapa ett program baserat på den här skärmen.

Redigera program.cs (Razor Pages, MVC Common)

Lägg till de definitioner som krävs för cookie-autentisering i Program.cs. De namnrymder som ska läggas till är följande:

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

Här är builder.Services koden som ska läggas till i .

// === 省略 ===

// 「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 Du kan aktivera cookie-autentisering genom att köra metoden och. Om du inte behöver ändra schemanamnet CookieAuthenticationDefaults.AuthenticationScheme anger du .

AddAuthorization Om du options.FallbackPolicy RequireAuthenticatedUser anger för metoden Du kan tillämpa en princip som krävs för autentisering på alla sidor, alla kontrollanter och åtgärder. Om du vill kräva autentisering för något annat än inloggningsskärmen är det en användbar metod när det gäller att minska koden och förhindra fel i beskrivningen. Du måste skriva kod som inte kräver autentisering för inloggningsskärmen separat.

Följande är app koden för .

// === 省略 ===

app.UseRouting();

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

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

// === 省略 ===

Eftersom vi vill lägga till autentiseringsfunktioner i applikationen app.UseAuthentication() kommer vi att lägga till . Beskrivningens plats är enligt MSDN-dokumentationen, app. UseAuthorization(). I övrigt är det fortfarande en mall.

Program för Razor Pages-projekt

Skapa en inloggningssida (Pages/Account/Login.cshtml.cs)

Skapa en fil

Skapa en inloggningssida. Filsökvägen ska skapas som "/Pages/Account/Login.cshtml". Detta beror på att standardinloggningssökvägen är sådan. Om du vill ändra den här sökvägen kan du Program.cs göra det genom att ange argumentet för metoden för AddCookie .

Du kan skapa det genom att kopiera andra filer istället för att skapa det från menyn, men i så fall, fixa programmet korrekt.

Tillåt användare att komma åt inloggningssidan utan att logga in

Program.cs Eftersom alla sidor endast kan nås när du är inloggad behöver du bara ställa in inloggningssidan så att du kan komma åt den även om du inte är inloggad.

AllowAnonymous Genom att lägga till attribut kan målsidan nås även om den inte är autentiserad. AllowAnonymous Attribut kan användas på andra ställen än på inloggningsskärmen, till exempel API-åtgärder som inte är relaterade till cookie-autentisering.

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

Skapa en variabel för att ta emot indata

När du loggar in anger du ditt användarnamn för att kunna ta emot dessa värden eftersom du anger ditt lösenord.

// 省略

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

Definiera ett användarnamn och lösenord för inloggningsautentisering

Ursprungligen skulle den lagras i en databas etc., men eftersom användarens bedömning inte är huvudfokus den här gången kommer jag att göra det som en tillfällig plats.

// 省略

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

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

Inloggningsprocess

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

Detta är autentiseringsprocessen efter att ha tryckt på inloggningsknappen. Om användarnamn och lösenord stämmer överens är autentisering möjlig.

Den kod som beskrivs är den minsta kod som krävs för autentiseringClaimClaimsIdentityClaimsPrincipal och HttpContext.SignInAsync Genom att anropa metoden genereras och autentiseras en cookie.

Om ytterligare anspråk krävs eller om cookiens förfallodatum krävs läggs ytterligare parametrar till.

När du har loggat in omdirigeras du till , där /Index autentisering krävs.

Utloggningsprocess

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

Logout När den används med en hanterare bearbetas den för att logga ut. HttpContext.SignOutAsync Genom att anropa metoden kan du ta bort cookien och återställa den till ett tillstånd där du inte är inloggad.

Skapa en vy

Vi tar inte hänsyn till utseendet. Lägg till fält för att ange ditt användarnamn och lösenord som visas nedan och placera en knapp för att logga in. Du bör också ha en länk för att komma åt utan att logga in för /Index testning.

Eftersom det är besvärligt att ange användarnamn och lösenord är det initiala värdet inställt.

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

Skapa en utloggningslänk (/Pages/Shared/_Layout.cshtml)

Vi kommer inte att göra några ändringar på startskärmen, men vi kommer att placera en utloggningslänk i navigeringsfältet. För att testa, lägg också upp en länk som tar dig till inloggningsskärmen utan att logga ut.

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

Det var allt för Razor Pages-koden.

Program för MVC-projekt

Skapa en inloggningsmodell

Du har skapat en modell för att ta emot de värden som anges på inloggningsskärmen.

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

Skapa en AccountController

Skapa de kontroller och åtgärder som krävs för att skapa inloggningsskärmen. Skapa kontrollantens namn AccountController som . Detta beror på att kontrollantens namn och åtgärdsnamn på inloggningsskärmen som standard är inställda på "~/Account/Login". Om du vill ändra den här sökvägen kan du göra det i alternativen AddCookie för metoden i Program.cs. För tillfället fortsätter vi med standardinställningarna.

Först ska vi skapa kontrollantsidan.

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 Genom att bevilja attributet kan alla åtgärder i det utföras utan att autentiseras. Detta gör att du endast kan komma åt inloggningsskärmen utan autentisering.

AllowAnonymous Attribut kan också användas i API-kontroller som inte är relaterade till cookie-autentisering på andra ställen än inloggningsskärmen.

Definiera sedan de användare och lösenord som kan logga in. Ursprungligen skulle den lagras i en databas etc., men eftersom användarens bedömning inte är huvudfokus den här gången kommer jag att göra det som en tillfällig plats.

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

Följande är en åtgärd som visar inloggningsskärmen. Eftersom den bara visas returneras vyn som den är.

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

Nedan visas koden som ska behandlas vid inloggning.

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

Detta är autentiseringsprocessen efter att ha tryckt på inloggningsknappen. Om användarnamn och lösenord stämmer överens är autentisering möjlig.

Den kod som beskrivs är den minsta kod som krävs för autentiseringClaimClaimsIdentityClaimsPrincipal och HttpContext.SignInAsync Genom att anropa metoden genereras och autentiseras en cookie.

Om ytterligare anspråk krävs eller om cookiens förfallodatum krävs läggs ytterligare parametrar till.

När du har loggat in omdirigeras du till , där ~/Home/Index autentisering krävs.

Slutligen läggs utloggningsprocessen till.

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

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

HttpContext.SignOutAsync Genom att anropa metoden kan du ta bort cookien och återställa den till ett tillstånd där du inte är inloggad.

Skapa en vy (inloggningsformulär) (/Views/Account/Login.cshtml)

Login Högerklicka på åtgärden för att lägga till en vy. Du kan också skapa den genom att kopiera den från en annan fil.

Vi tar inte hänsyn till utseendet. Lägg till fält för att ange ditt användarnamn och lösenord som visas nedan och placera en knapp för att logga in. Du bör också ha en länk för att komma åt utan att logga in för Home/Index testning.

Eftersom det är besvärligt att ange användarnamn och lösenord är det initiala värdet inställt.

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

Skapa en utloggningslänk (/Views/Shared/_Layout.cshtml)

Vi kommer inte att göra några ändringar på startskärmen, men vi kommer att placera en utloggningslänk i navigeringsfältet. För att testa, lägg också upp en länk som tar dig till inloggningsskärmen utan att logga ut.

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

Det var allt för MVC-koden.

Bekräftelse av drift

Detta slutför den minsta nödvändiga implementeringen av cookie-autentisering. Prova att köra den och se hur den fungerar. Beteendet bör ändras beroende på om du är inloggad eller inte. Som ett enkelt exempel kan du se följande beteende.

Drift driftresultat
Gå hem utan att logga in Omdirigera till inloggningsskärmen
logga in Gå till startskärmen
Logga ut hemifrån och gå hem utan att logga in Omdirigera till inloggningsskärmen
Gå hem utan att logga ut från bostaden och logga in Gå till startskärmen