Créez un mécanisme de connexion à l’aide de l’authentification par cookie et créez un mécanisme pour être redirigé si vous n’êtes pas authentifié

Page mise à jour :
Date de création de la page :

Environnement d’exploitation

Visual Studio
  • Communauté Visual Studio 2022
ASP.NET Core (MVC, Razor Pages)
6.0

Au début

Cette fois-ci, ASP.NET Core utilisera l’authentification par cookie comme mécanisme d’authentification de connexion. Vous pouvez considérer l’authentification par cookie comme étant similaire à l’authentification par formulaire traditionnel.

Un autre mécanisme d’authentification pour ASP.NET Core est ASP.NET Core Identity. En plus de l’authentification à l’aide de formulaires, cela vous permet de vous authentifier avec des API, d’utiliser des services de connexion externes, de gérer et de réinitialiser les mots de passe, etc. Vous pouvez utiliser de nombreuses fonctionnalités. Cependant, du point de vue de la création d’un simple écran de connexion cette fois-ci, il s’agira d’un mécanisme d’authentification quelque peu exagéré. Nous ne l’utiliserons pas cette fois-ci.

Dans les conseils d’authentification des cookies introduits cette fois-ci, vous ne pouvez rien afficher d’autre que l’écran de connexion à moins que vous ne vous connectiez. Si vous essayez de naviguer vers un autre écran, vous serez redirigé vers l’écran de connexion. Si vous vous connectez, vous pouvez afficher d’autres écrans.

Pour l’instant, vous pouvez vous connecter en saisissant votre nom d’utilisateur et votre mot de passe sur l’écran de connexion. L’authentification de l’utilisateur elle-même est implémentée en tant que lieu temporaire. Dans ce cas, l’accent est mis sur la mise en œuvre de l’authentification par cookie, de sorte que l’essence du processus de détermination, par exemple si le mot de passe est correct, n’est pas l’essentiel.

Cette astuce ne décrit qu’une partie du programme. Pour le code complet, téléchargez le programme complet. Il couvre également les frameworks MVC et Razor Pages.

Créer un projet

Démarrez Visual Studio et créez un projet.

Pour Razor Pages, sélectionnez ASP.NET Core Web App ou, pour MVC, sélectionnez ASP.NET Core Web App (Model-View-Controller).

Spécifiez le nom du projet de votre choix et l’emplacement du projet.

Pour le type d’authentification, sélectionnez « Aucune ». Si vous choisissez une autre authentification, vous utiliserez ASP.NET Core Identity. Lorsque vous avez terminé avec les paramètres, cliquez sur le bouton « Créer ».

Après la création du projet, l’écran ci-dessous s’affiche lors de l’exécution du débogage. Nous allons créer un programme basé sur cet écran.

Modifier le programme.cs (Razor Pages, MVC Common)

Ajoutez les définitions requises pour l’authentification des cookies à Program.cs. Les espaces de noms à ajouter sont les suivants :

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

builder.Services Voici le code à ajouter à .

// === 省略 ===

// 「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 Vous pouvez activer l’authentification des cookies en exécutant la méthode and. Si vous n’avez pas besoin de modifier le nom du schéma, CookieAuthenticationDefaults.AuthenticationScheme spécifiez .

AddAuthorization Si vous options.FallbackPolicy RequireAuthenticatedUser spécifiez pour la méthode Vous pouvez appliquer une stratégie d’authentification requise à toutes les pages, à tous les contrôleurs et à toutes les actions. Si vous souhaitez exiger une authentification pour autre chose que l’écran de connexion, il s’agit d’une méthode utile pour réduire le code et éviter les erreurs dans la description. Vous devrez écrire séparément du code qui ne nécessite pas d’authentification pour l’écran de connexion.

Vous trouverez ci-dessous app le code de .

// === 省略 ===

app.UseRouting();

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

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

// === 省略 ===

Puisque nous voulons ajouter une fonctionnalité d’authentification à l’application, app.UseAuthentication() nous allons ajouter . L’emplacement de la description est conforme à la documentation MSDN, app. UseAuthorization(). En dehors de cela, il s’agit toujours d’un modèle.

Programmes pour les projets Razor Pages

Créer une page de connexion (Pages/Account/Login.cshtml.cs)

Créer un fichier

Créez une page de connexion. Le chemin d’accès au fichier doit être créé sous la forme « /Pages/Account/Login.cshtml ». C’est parce que le chemin de connexion par défaut est comme ça. Si vous souhaitez modifier ce chemin, vous Program.cs pouvez le faire en définissant l’argument de la AddCookie méthode de .

Vous pouvez le créer en copiant d’autres fichiers au lieu de le créer à partir du menu, mais dans ce cas, veuillez corriger le programme correctement.

Autoriser les utilisateurs à accéder à la page de connexion sans se connecter

Program.cs Étant donné que toutes les pages ne sont accessibles que lorsque vous êtes connecté, vous devez définir uniquement la page de connexion afin de pouvoir y accéder même si vous n’êtes pas connecté.

AllowAnonymous En ajoutant des attributs, la page cible est accessible même si elle n’est pas authentifiée. AllowAnonymous Les attributs peuvent être utilisés à d’autres endroits que l’écran de connexion, tels que des opérations d’API sans rapport avec l’authentification des cookies.

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

Créer une variable pour recevoir une entrée

Lorsque vous vous connectez, vous déclarez votre nom d’utilisateur pour pouvoir recevoir ces valeurs car vous entrez votre mot de passe.

// 省略

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

Définir un nom d’utilisateur et un mot de passe pour l’authentification de connexion

À l’origine, il devait être stocké dans une base de données, etc., mais comme le jugement de l’utilisateur n’est pas l’objectif principal cette fois-ci, je vais en faire un endroit temporaire.

// 省略

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

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

Processus de connexion

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

Il s’agit du processus d’authentification après avoir appuyé sur le bouton de connexion. Si le nom d’utilisateur et le mot de passe correspondent, l’authentification est possible.

Le code décrit est le code minimum requis pour l’authentification,ClaimClaimsIdentityClaimsPrincipal et HttpContext.SignInAsync En appelant la méthode, un cookie est généré et authentifié.

Si des revendications supplémentaires sont requises ou si l’expiration du cookie est requise, des paramètres supplémentaires sont ajoutés.

Après vous être connecté, vous êtes redirigé vers , où /Index l’authentification est requise.

Processus de déconnexion

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

Logout Lorsqu’il est accédé avec un gestionnaire, il est traité pour se déconnecter. HttpContext.SignOutAsync En appelant la méthode, vous pouvez supprimer le cookie et le ramener à un état où vous n’êtes pas connecté.

Création d’une vue

Nous ne tenons pas compte de l’apparence. Ajoutez des champs pour saisir votre nom d’utilisateur et votre mot de passe comme indiqué ci-dessous, et placez un bouton pour vous connecter. Vous devriez également disposer d’un lien pour y accéder sans vous connecter pour /Index tester.

Comme il est difficile de saisir le nom d’utilisateur et le mot de passe, la valeur initiale est définie.

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

Créer un lien de déconnexion (/Pages/Shared/_Layout.cshtml)

Nous n’apporterons aucune modification à l’écran d’accueil, mais nous mettrons un lien de déconnexion dans la barre de navigation. De plus, pour les tests, publiez un lien qui vous amène à l’écran de connexion sans vous déconnecter.

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

C’est tout pour le code Razor Pages.

Programmes pour les projets MVC

Création d’un modèle de connexion

Vous avez créé un modèle pour recevoir les valeurs saisies sur l’écran de connexion.

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

Création d’un AccountController

Créez les contrôleurs et les actions nécessaires à la création de l’écran de connexion. Créez le nom AccountController du contrôleur sous la forme . En effet, par défaut, le nom du contrôleur et le nom de l’action sur l’écran de connexion sont définis sur « ~/Account/Login ». Si vous souhaitez modifier ce chemin, vous pouvez le faire dans les options de AddCookie la méthode dans Program.cs. Pour l’instant, nous allons procéder avec les paramètres par défaut.

Tout d’abord, créons le côté contrôleur.

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 En accordant l’attribut, toutes les actions qu’il contient peuvent être effectuées sans être authentifiées. Cela vous permet d’accéder uniquement à l’écran de connexion sans authentification.

AllowAnonymous Les attributs peuvent également être utilisés dans les contrôleurs API uniquement qui ne sont pas liés à l’authentification des cookies à d’autres endroits que l’écran de connexion.

Ensuite, définissez les utilisateurs et les mots de passe qui peuvent se connecter. À l’origine, il devait être stocké dans une base de données, etc., mais comme le jugement de l’utilisateur n’est pas l’objectif principal cette fois-ci, je vais en faire un endroit temporaire.

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

Ce qui suit est une action qui affiche l’écran de connexion. Puisqu’il n’est qu’affiché, il renvoie la vue telle quelle.

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

Vous trouverez ci-dessous le code à traiter lors de la connexion.

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

Il s’agit du processus d’authentification après avoir appuyé sur le bouton de connexion. Si le nom d’utilisateur et le mot de passe correspondent, l’authentification est possible.

Le code décrit est le code minimum requis pour l’authentification,ClaimClaimsIdentityClaimsPrincipal et HttpContext.SignInAsync En appelant la méthode, un cookie est généré et authentifié.

Si des revendications supplémentaires sont requises ou si l’expiration du cookie est requise, des paramètres supplémentaires sont ajoutés.

Après vous être connecté, vous êtes redirigé vers , où ~/Home/Index l’authentification est requise.

Enfin, le processus de déconnexion est ajouté.

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

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

HttpContext.SignOutAsync En appelant la méthode, vous pouvez supprimer le cookie et le ramener à un état où vous n’êtes pas connecté.

Créer une vue (formulaire de connexion) (/Views/Account/Login.cshtml)

Login Cliquez avec le bouton droit de la souris sur l’action pour ajouter une vue. Vous pouvez également le créer en le copiant à partir d’un autre fichier.

Nous ne tenons pas compte de l’apparence. Ajoutez des champs pour saisir votre nom d’utilisateur et votre mot de passe comme indiqué ci-dessous, et placez un bouton pour vous connecter. Vous devriez également disposer d’un lien pour y accéder sans vous connecter pour Home/Index tester.

Comme il est difficile de saisir le nom d’utilisateur et le mot de passe, la valeur initiale est définie.

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

Créer un lien de déconnexion (/Views/Shared/_Layout.cshtml)

Nous n’apporterons aucune modification à l’écran d’accueil, mais nous mettrons un lien de déconnexion dans la barre de navigation. De plus, pour les tests, publiez un lien qui vous amène à l’écran de connexion sans vous déconnecter.

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

C’est tout pour le code MVC.

Confirmation de fonctionnement

Cela complète la mise en œuvre minimale requise de l’authentification des cookies. Essayez de l’exécuter et voyez comment cela fonctionne. Le comportement devrait changer selon que vous êtes connecté ou non. À titre d’exemple simple, vous pouvez voir le comportement suivant.

Fonctionnement résultat de l’opération
Rentrer chez soi sans se connecter Rediriger vers l’écran de connexion
connectez-vous Accéder à l’écran d’accueil
Déconnectez-vous de la maison et rentrez chez vous sans vous connecter Rediriger vers l’écran de connexion
Rentrer chez soi sans se déconnecter de la maison et se connecter Accéder à l’écran d’accueil