צור מנגנון התחברות באמצעות אימות קובצי Cookie, וצור מנגנון לניתוב מחדש אם אינך מאומת

עודכן דף :
תאריך יצירת דף :

סביבת הפעלה

Visual Studio
  • קהילת Visual Studio 2022
ASP.NET Core (MVC, דפי גילוח)
6.0

בהתחלה

הפעם, ASP.NET Core ישתמש באימות קובצי Cookie כמנגנון אימות התחברות. אתה יכול לחשוב על אימות קובצי Cookie כדומה לאימות טפסים מסורתי.

מנגנון אימות נוסף עבור ASP.NET Core הוא ASP.NET Core Identity. בנוסף לאימות באמצעות טפסים, זה מאפשר לך לבצע אימות באמצעות ממשקי API, להשתמש בשירותי התחברות חיצוניים, לנהל ולאפס סיסמאות וכו '. אתה יכול להשתמש בהרבה תכונות. עם זאת, מנקודת המבט של יצירת מסך כניסה פשוט הפעם, זה יהיה מנגנון אימות מוגזם במקצת. לא נשתמש בו הפעם.

בטיפים לאימות קובצי Cookie שהוצגו הפעם, אינך יכול להציג דבר מלבד מסך הכניסה אלא אם כן אתה מתחבר. אם תנסה לנווט למסך אחר, תנותב מחדש למסך ההתחברות. אם אתה מתחבר, אתה יכול להציג מסכים אחרים.

לעת עתה, תוכל להתחבר על ידי הזנת שם המשתמש והסיסמה שלך במסך ההתחברות. אימות המשתמש עצמו מיושם כמקום זמני. במקרה זה, ההתמקדות העיקרית היא ביישום אימות עוגיות, ולכן מהות תהליך הקביעה כגון האם הסיסמה נכונה אינה המהות.

עצה זו מתארת רק חלק מהתוכנית. לקבלת הקוד המלא, הורד את התוכנית המלאה. הוא מכסה גם מסגרות MVC ו-Razor Pages.

יצירת פרוייקט

הפעל את Visual Studio וצור פרוייקט חדש.

עבור דפי גילוח, בחר ASP.NET Core Web App, או עבור MVC, בחר ASP.NET Core Web App (Model-View-Controller).

ציין שם פרוייקט לפי בחירתך ומיקום עבור הפרוייקט.

עבור סוג האימות, בחר "ללא". אם תבחר באימות אחר, תשתמש בזהות הליבה ASP.NET. כשתסיים עם ההגדרות, לחץ על הלחצן "צור".

לאחר יצירת הפרויקט, המסך המוצג להלן יוצג בעת ביצוע איתור באגים. אנו ניצור תוכנית המבוססת על מסך זה.

ערוך תוכנית.cs (דפי גילוח, MVC נפוץ)

הוסף את ההגדרות הדרושות לאימות קבצי Cookie לתוכנית.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 באפשרותך להפעיל אימות קובצי Cookie על-ידי הפעלת פעולת השירות ו- . אם אינך צריך לשנות את שם הסכימה, 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(). חוץ מזה, זו עדיין תבנית.

תוכניות לפרויקטים של דפי גילוח

יצירת דף כניסה (Pages/Account/Login.cshtml.cs)

יצירת קובץ

צור דף התחברות. יש ליצור את נתיב הקובץ כ- "/Pages/Account/Login.cshtml". הסיבה לכך היא שנתיב הכניסה המוגדר כברירת מחדל הוא כזה. אם ברצונך לשנות נתיב זה, באפשרותך Program.cs לעשות זאת על-ידי הגדרת הארגומנט של פעולת השירות של AddCookie .

אתה יכול ליצור אותו על ידי העתקת קבצים אחרים במקום ליצור אותו מהתפריט, אבל במקרה זה, אנא תקן את התוכנית כראוי.

אפשר למשתמשים לגשת לדף הכניסה מבלי להיכנס

Program.cs מכיוון שניתן לגשת לכל הדפים רק כאשר אתה מחובר, עליך להגדיר רק את דף הכניסה כך שתוכל לגשת אליו גם אם אינך מחובר.

AllowAnonymous על ידי הוספת תכונות, ניתן לגשת לעמוד היעד גם אם הוא אינו מאומת. AllowAnonymous ניתן להשתמש בתכונות במקומות אחרים מלבד מסך ההתחברות, כגון פעולות API שאינן קשורות לאימות קובצי 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
  {
  }
}

יצירת משתנה לקבלת קלט

כאשר אתה מתחבר, אתה מצהיר על שם המשתמש שלך כדי שתוכל לקבל ערכים אלה מכיוון שאתה מזין את הסיסמה שלך.

// 省略

[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 על ידי קריאה לשיטה, קובץ Cookie נוצר ומאומת.

אם נדרשות תביעות נוספות או שתוקף קובצי Cookie נדרש, מתווספים פרמטרים נוספים.

לאחר הכניסה, אתה מנותב מחדש אל , שבו /Index נדרש אימות.

תהליך התנתקות

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

Logout כאשר ניגשים אליו עם מטפל, הוא מעובד כדי להתנתק. HttpContext.SignOutAsync על ידי קריאה לשיטה, תוכל למחוק את קובץ ה- Cookie ולהחזיר אותו למצב שבו אינך מחובר.

יצירת תצוגה

אנחנו לא לוקחים בחשבון את המראה. הוסף שדות להזנת שם המשתמש והסיסמה שלך כפי שמוצג להלן, והצב לחצן כדי להיכנס. כמו כן, אמור להיות לך קישור לגישה מבלי להיכנס לבדיקה /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"); }
}

יצירת קישור התנתקות (/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 הבקר כ- . הסיבה לכך היא שכברירת מחדל, שם הבקר ושם הפעולה במסך הכניסה מוגדרים כ- "~/Account/Login". אם ברצונך לשנות נתיב זה, באפשרותך לעשות זאת באפשרויות 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 בלבד שאינם קשורים לאימות קובצי Cookie במקומות אחרים מלבד מסך ההתחברות.

לאחר מכן, הגדר את המשתמשים והסיסמאות שיכולים להיכנס. במקור, זה היה מאוחסן במסד נתונים, וכו ', אבל מאז שיקול דעת המשתמש הוא לא המוקד העיקרי הפעם, אני אעשה את זה כמקום זמני.

[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 על ידי קריאה לשיטה, קובץ Cookie נוצר ומאומת.

אם נדרשות תביעות נוספות או שתוקף קובצי Cookie נדרש, מתווספים פרמטרים נוספים.

לאחר הכניסה, אתה מנותב מחדש אל , שבו ~/Home/Index נדרש אימות.

לבסוף, תהליך ההתנתקות מתווסף.

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

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

HttpContext.SignOutAsync על ידי קריאה לשיטה, תוכל למחוק את קובץ ה- Cookie ולהחזיר אותו למצב שבו אינך מחובר.

יצירת תצוגה (טופס כניסה) (/Views/Account/Login.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"); }
}

יצירת קישור התנתקות (/Views/Shared/_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.

אישור פעולה

פעולה זו משלימה את היישום המינימלי הנדרש של אימות קובצי Cookie. נסה להפעיל אותו ולראות איך זה עובד. אופן הפעולה אמור להשתנות בהתאם לשאלה אם אתה מחובר או לא. כדוגמה פשוטה, ניתן לראות את אופן הפעולה הבא.

פעולת תוצאת הפעולה
חזור הביתה מבלי להתחבר ניתוב מחדש למסך הכניסה
כניסה מעבר למסך הבית
התנתק מהבית וחזור הביתה מבלי להתחבר ניתוב מחדש למסך הכניסה
ללכת הביתה בלי לצאת מהבית ולהתחבר מעבר למסך הבית