ایجاد یک مکانیسم ورود با استفاده از احراز هویت کوکی، و ایجاد یک مکانیسم برای هدایت اگر شما احراز هویت نیست

صفحه به روز شده :
تاریخ ایجاد صفحه :

محیط عملیاتی

ویژوال استودیو
  • ویژوال استودیو جامعه 2022
هسته ASP.NET (MVC، Razor Pages)
6.0

در ابتدا

این بار، ASP.NET Core از احراز هویت کوکی به عنوان مکانیسم احراز هویت ورود استفاده خواهد کرد. شما می توانید از احراز هویت کوکی به عنوان شبیه به احراز هویت فرم های سنتی فکر می کنم.

یکی دیگر از مکانیسم های احراز هویت برای ASP.NET Core ASP.NET Core Identity است. علاوه بر احراز هویت با استفاده از فرم ها، این به شما اجازه می دهد تا با API ها تایید اعتبار کنید، از خدمات ورود خارجی استفاده کنید، رمزهای عبور را مدیریت و تنظیم مجدد کنید و غیره. شما می توانید از بسیاری از ویژگی ها استفاده کنید. با این حال، از دیدگاه ایجاد یک صفحه ورود ساده این بار، این یک مکانیسم احراز هویت تا حدودی اغراق امیز خواهد بود. این بار از ان استفاده نخواهیم کرد.

در نکات احراز هویت کوکی که این بار معرفی شده است، نمی توانید چیزی غیر از صفحه ورود را نمایش دهید مگر اینکه وارد سیستم شوید. اگر سعی کنید به صفحه دیگری بروید، به صفحه ورود هدایت خواهید شد. اگر وارد سیستم شوید، می توانید صفحه های دیگر را مشاهده کنید.

در حال حاضر می توانید با وارد کردن نام کاربری و رمز عبور خود در صفحه ورود وارد سیستم شوید. احراز هویت کاربر خود به عنوان یک مکان موقت اجرا می شود. در این مورد، تمرکز اصلی بر اجرای احراز هویت کوکی است، بنابراین جوهر فرایند تعیین مانند اینکه ایا رمز عبور درست است، جوهر نیست.

این نکته فقط بخشی از برنامه را توصیف می کند. برای کد کامل، برنامه کامل را دانلود کنید. همچنین هر دو چارچوب MVC و Razor Pages را پوشش می دهد.

ایجاد یک پروژه

Visual Studio را شروع کنید و یک پروژه جدید ایجاد کنید.

برای Razor Pages، ASP.NET Core Web App را انتخاب کنید یا برای MVC، برنامه وب Core ASP.NET (Model-View-Controller) را انتخاب کنید.

یک نام پروژه را به انتخاب خود و یک مکان برای پروژه مشخص کنید.

برای نوع احراز هویت، "None" را انتخاب کنید. اگر احراز هویت دیگری را انتخاب کنید، از ASP.NET Core Identity استفاده خواهید کرد. هنگامی که تنظیمات را انجام می دهید، روی دکمه "ایجاد" کلیک کنید.

پس از ایجاد پروژه، صفحه نمایش نشان داده شده در زیر هنگام اجرای اشکال زدایی نمایش داده می شود. ما یک برنامه بر اساس این صفحه ایجاد کنید.

ویرایش برنامه.cs (Razor Pages، MVC Common)

تعاریف مورد نیاز برای احراز هویت کوکی را به Program.cs اضافه کنید. فضاهای نام اضافه شده به شرح زیر است:

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

در اینجا builder.Services کد برای اضافه کردن به .

// === 省略 ===

// 「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 شما می توانید احراز هویت کوکی با اجرای و روش را فعال کنید. اگر نیازی به تغییر نام طرح ندارید، CookieAuthenticationDefaults.AuthenticationScheme مشخص کنید.

AddAuthorization اگر برای روش مشخص کنید options.FallbackPolicy RequireAuthenticatedUser شما می توانید یک سیاست احراز هویت مورد نیاز برای تمام صفحات، تمام کنترل کننده ها و اقدامات اعمال کنید. اگر می خواهید برای هر چیزی غیر از صفحه ورود به سیستم نیاز به احراز هویت داشته باشید، این یک روش مفید از نظر کاهش کد و جلوگیری از خطا در توضیحات است. شما باید کدی را بنویسید که برای صفحه ورود به سیستم به طور جداگانه نیازی به احراز هویت نداشته باشد.

کد زیر برای است app .

// === 省略 ===

app.UseRouting();

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

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

// === 省略 ===

از انجا که ما می خواهیم قابلیت احراز هویت را به برنامه اضافه کنیم، app.UseAuthentication() اضافه خواهیم کرد. محل توصیف با توجه به مستندات MSDN، برنامه است. UseAuthorization() به غیر از این، هنوز یک الگو است.

برنامه های پروژه های Razor Pages

ایجاد یک صفحه ورود (صفحات / حساب / Login.cshtml.cs)

ایجاد یک پرونده

یک صفحه ورود ایجاد کنید. مسیر فایل باید به صورت "/Pages/Account/Login.cshtml" ایجاد شود. این به این دلیل است که مسیر ورود به سیستم به طور پیش فرض اینگونه است. اگر می خواهید این مسیر را تغییر دهید، می توانید Program.cs این کار را با تنظیم استدلال AddCookie روش انجام دهید.

شما می توانید ان را با کپی کردن فایل های دیگر به جای ایجاد ان از منو ایجاد کنید، اما در این صورت، لطفا برنامه را به درستی اصلاح کنید.

اجازه دادن به کاربران برای دسترسی به صفحه ورود بدون ورود به سیستم

Program.cs از انجا که تمام صفحات تنها زمانی قابل دسترسی هستند که وارد سیستم شوید، باید فقط صفحه ورود را تنظیم کنید تا بتوانید به ان دسترسی پیدا کنید حتی اگر وارد سیستم نشده باشید.

AllowAnonymous با اضافه کردن ویژگی ها، صفحه هدف می تواند قابل دسترسی باشد حتی اگر تایید نشده باشد. AllowAnonymous ویژگی ها ممکن است در مکان های دیگر غیر از صفحه ورود، مانند عملیات API غیر مرتبط با احراز هویت کوکی استفاده شود.

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

ایجاد یک متغیر برای دریافت ورودی

هنگامی که وارد سیستم می شوید، نام کاربری خود را اعلام می کنید تا بتوانید این مقادیر را دریافت کنید زیرا رمز عبور خود را وارد می کنید.

// 省略

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

تعریف یک نام کاربری و رمز عبور برای احراز هویت ورود

در اصل، ان را در یک پایگاه داده ذخیره می شود، و غیره، اما از انجا که قضاوت کاربر این بار تمرکز اصلی نیست، من ان را به عنوان یک مکان موقت.

// 省略

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

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

فرایند ورود

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

این فرایند احراز هویت پس از فشار دادن دکمه ورود است. اگر نام کاربر و رمز عبور مطابقت داشته باشد، احراز هویت امکان پذیر است.

کد توصیف شده حداقل کد مورد نیاز برای احراز هویتClaimClaimsIdentityClaimsPrincipal است و HttpContext.SignInAsync با فراخوانی روش، یک کوکی تولید و تایید می شود.

اگر ادعاهای اضافی مورد نیاز باشد یا انقضای کوکی مورد نیاز باشد، پارامترهای اضافی اضافه می شود.

پس از ورود به سیستم، شما به جایی که /Index احراز هویت لازم است هدایت می شوید.

فرایند خروج

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

Logout هنگامی که با یک گرداننده قابل دسترسی است، پردازش می شود تا از سیستم خارج شود. HttpContext.SignOutAsync با تماس با روش، می توانید کوکی را حذف کنید و ان را به وضعیتی که وارد ان نشده اید بازگردانید.

ایجاد یک View

ما ظاهر را در نظر نمی گیریم. فیلدهایی را برای وارد کردن نام کاربری و رمز عبور خود اضافه کنید که در زیر نشان داده شده است و یک دکمه برای ورود به سیستم قرار دهید. شما همچنین باید یک لینک برای دسترسی بدون ورود به سیستم برای /Index ازمایش داشته باشید.

از انجا که وارد کردن نام کاربری و رمز عبور مشکل است، مقدار اولیه تعیین می شود.

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

ایجاد یک لینک logout (/Pages/Shared/_Layout.cshtml)

ما هیچ تغییری در صفحه اصلی ایجاد نخواهیم کرد، اما یک لینک خروج از سیستم را در نوار ناوبری قرار می دهیم. همچنین، برای ازمایش، یک لینک ارسال کنید که شما را به صفحه ورود بدون خروج از سیستم می برد.

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

این برای کد Razor Pages است.

برنامه های پروژه های MVC

ایجاد یک مدل ورود

شما یک مدل برای دریافت مقادیر وارد شده در صفحه ورود ایجاد کرده اید.

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

ایجاد یک AccountController

کنترل کننده ها و اقدامات مورد نیاز برای ایجاد صفحه ورود را ایجاد کنید. ایجاد نام AccountController کنترل کننده به عنوان . این به این دلیل است که به طور پیش فرض، نام کنترل کننده و نام عمل در صفحه ورود به "~ / حساب / ورود" تنظیم شده است. اگر می خواهید این مسیر را تغییر دهید، می توانید این کار را در گزینه های AddCookie روش در برنامه.cs انجام دهید. در حال حاضر، ما با تنظیمات پیش فرض ادامه خواهیم داد.

اول، بیایید طرف کنترل کننده را ایجاد کنیم.

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 با اعطای ویژگی، تمام اقدامات در ان می تواند بدون احراز هویت انجام شود. این اجازه می دهد تا شما را به دسترسی به تنها صفحه ورود بدون احراز هویت.

AllowAnonymous ویژگی ها همچنین ممکن است در کنترل کننده های فقط API استفاده شوند که مربوط به احراز هویت کوکی در مکان های دیگر به غیر از صفحه ورود نیستند.

بعد، کاربران و رمزهای عبور را که می توانند وارد سیستم شوند تعریف کنید. در اصل، ان را در یک پایگاه داده ذخیره می شود، و غیره، اما از انجا که قضاوت کاربر این بار تمرکز اصلی نیست، من ان را به عنوان یک مکان موقت.

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

در زیر یک عمل است که صفحه ورود به سیستم را نشان می دهد. از انجا که فقط نمایش داده می شود، منظره را همانطور که هست باز می گرداند.

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

در زیر کدی است که هنگام ورود به سیستم پردازش می شود.

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

این فرایند احراز هویت پس از فشار دادن دکمه ورود است. اگر نام کاربر و رمز عبور مطابقت داشته باشد، احراز هویت امکان پذیر است.

کد توصیف شده حداقل کد مورد نیاز برای احراز هویتClaimClaimsIdentityClaimsPrincipal است و HttpContext.SignInAsync با فراخوانی روش، یک کوکی تولید و تایید می شود.

اگر ادعاهای اضافی مورد نیاز باشد یا انقضای کوکی مورد نیاز باشد، پارامترهای اضافی اضافه می شود.

پس از ورود به سیستم، شما به جایی که ~/Home/Index احراز هویت لازم است هدایت می شوید.

در نهایت، فرایند خروج اضافه می شود.

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

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

HttpContext.SignOutAsync با تماس با روش، می توانید کوکی را حذف کنید و ان را به وضعیتی که وارد ان نشده اید بازگردانید.

ایجاد نما (فرم ورود) (/نمایش/حساب/ورود.cshtml)

Login برای افزودن نما روی کنش کلیک راست کنید. شما همچنین می توانید ان را با کپی کردن ان از یک فایل دیگر ایجاد کنید.

ما ظاهر را در نظر نمی گیریم. فیلدهایی را برای وارد کردن نام کاربری و رمز عبور خود اضافه کنید که در زیر نشان داده شده است و یک دکمه برای ورود به سیستم قرار دهید. شما همچنین باید یک لینک برای دسترسی بدون ورود به سیستم برای Home/Index ازمایش داشته باشید.

از انجا که وارد کردن نام کاربری و رمز عبور مشکل است، مقدار اولیه تعیین می شود.

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

ایجاد یک لینک خروج از سیستم (/نمایش ها / به اشتراک گذاشته شده / _Layout.cshtml)

ما هیچ تغییری در صفحه اصلی ایجاد نخواهیم کرد، اما یک لینک خروج از سیستم را در نوار ناوبری قرار می دهیم. همچنین، برای ازمایش، یک لینک ارسال کنید که شما را به صفحه ورود بدون خروج از سیستم می برد.

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

این برای کد MVC است.

تایید عملیات

این حداقل اجرای مورد نیاز برای احراز هویت کوکی را تکمیل می کند. سعی کنید ان را اجرا کنید و ببینید چگونه کار می کند. رفتار باید بسته به اینکه ایا شما وارد سیستم شده اید یا نه تغییر کند. به عنوان یک مثال ساده، می توانید رفتار زیر را ببینید.

عملیات نتیجه عملیات
رفتن به خانه بدون ورود به سیستم تغییر مسیر به صفحه ورود
ورود رفتن به صفحه اصلی
از خانه خارج شوید و بدون ورود به سیستم به خانه بروید تغییر مسیر به صفحه ورود
بدون خروج از خانه و ورود به سیستم به خانه بروید رفتن به صفحه اصلی