สร้างหน้าจอเข้าสู่ระบบหลายหน้าจอและจํากัดหน้าที่สามารถเข้าถึงได้โดยหน้าจอที่คุณเข้าสู่ระบบ

ปรับปรุงหน้า :
วันที่สร้างเพจ :

สภาพแวดล้อมในการทํางาน

วิชวลสตูดิโอ
  • ชุมชน Visual Studio 2022
ASP.NET Core (MVC, หน้ามีดโกน)
6.0

ทีแรก

ส่วนนี้อธิบายวิธีเตรียมหน้าจอเข้าสู่ระบบหลายหน้าจอในแอปพลิเคชันเดียว และแยกหน้าที่แต่ละหน้าจอเข้าสู่ระบบสามารถเข้าถึงได้ วิธีการสร้างหน้าจอเข้าสู่ระบบเดียวอธิบายไว้ใน "การสร้างกลไกการเข้าสู่ระบบโดยใช้การตรวจสอบคุกกี้และการสร้างกลไกที่จะเปลี่ยนเส้นทางหากคุณไม่ได้รับการตรวจสอบสิทธิ์" และเนื้อหานี้อธิบายบนสมมติฐานว่าคุณมีความรู้ในการสร้างหน้าจอเข้าสู่ระบบเดียว ดังนั้นกระบวนการเช่นเดียวกับหน้าจอเข้าสู่ระบบเดียวจึงเป็นเพียงคําอธิบายง่ายๆ

สร้างโครงการ

ฉันกําลังสร้างตัวอย่าง Razor Pages และ MVC แต่ไม่เป็นไรที่จะสร้างเฉพาะโปรเจ็กต์ที่คุณต้องการใช้

แก้ไขโปรแกรม.cs (หน้ามีดโกน, MVC ทั่วไป)

คราวนี้เราจะใช้วิธีการแยกหน้าที่สามารถเข้าถึงได้โดยหน้าเข้าสู่ระบบโดยใช้ชื่อ "สคีมา"

ขั้นแรก ให้เพิ่มเนมสเปซที่ด้านบนของโค้ด

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

ต่อไปนี้เป็นตัวสร้าง รหัสที่จะเพิ่มลงในบริการ

// === 省略 ===

// 「Razor Pages」のコード
// builder.Services.AddRazorPages();
// 「MVC」のコード
// builder.Services.AddControllersWithViews();

// ※ここから追加

// Cookie による認証スキームを追加する
builder.Services
  .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
  .AddCookie("FirstAuth", option =>
  {
    option.LoginPath = "/Account/LoginFirst";
  })
  .AddCookie("SecondAuth", option =>
  {
    option.LoginPath = "/Account/LoginSecond";
  });

builder.Services.AddAuthorization(options =>
{
  // 認証属性を設定していない画面は FirstAuth スキーマの認証が必要となる
  options.FallbackPolicy = new AuthorizationPolicyBuilder("FirstAuth")
    .RequireAuthenticatedUser()
    .Build();
});

// ※ここまで追加

var app = builder.Build();

// === 省略 ===

ความแตกต่างจากครั้งที่แล้วคือคุกกี้ถูกเพิ่มเป็นสอง AddCookie อาร์กิวเมนต์แรกของแต่ละรายการประกอบด้วยชื่อสคีมาที่ระบุการเข้าสู่ระบบ ชื่อนี้สามารถเป็นอะไรก็ได้ตราบใดที่เป็นชื่ออื่น อาร์กิวเมนต์ที่สองคือ URL ของหน้าเข้าสู่ระบบที่จะถูกเปลี่ยนเส้นทางเมื่อมีการเข้าถึงการเข้าสู่ระบบโดยไม่ต้องเข้าสู่ระบบ อย่างไรก็ตาม ถ้าคุณไม่ระบุชื่อสคีมา มันจะ CookieAuthenticationDefaults.AuthenticationScheme เหมือนกับ .

FallbackPolicyนอกจากนี้ยังระบุสคีมาเป็นการตั้งค่าสําหรับFirstAuth ด้วยเหตุนี้ จึงจําเป็นต้องเข้าถึงFirstAuthการรับรองความถูกต้องแบบไม่มีใครแตะต้องIndex.cshtmlหรือPrivacy.cshtmlสคีมานี้

รหัสสําหรับแอปต่อไปนี้เหมือนกับการเข้าสู่ระบบครั้งเดียว

// === 省略 ===

app.UseRouting();

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

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

// === 省略 ===

โปรแกรมสําหรับโครงการ Razor Pages

การสร้างหน้าหลังจากเข้าสู่ระบบ

สร้างสองหน้าหลังจากเข้าสู่ระบบ เนื่องจากเป็นหน้าที่แสดงเฉพาะ จึงไม่เป็นไรหากคุณสร้างเพื่อให้คุณสามารถดูตําแหน่งที่คุณเข้าสู่ระบบได้

หน้า/IndexFirst.cshtml

@page
@model IndexFirstModel
@{
  ViewData["Title"] = "First page";
}

<div class="text-center">
    <h1 class="display-4">First Page</h1>
</div>

ไม่มีอะไรสําคัญเป็นพิเศษเกี่ยวกับเรื่องนี้ แต่ตรวจสอบให้แน่ใจว่าโมเดลที่คุณกําลังอ้างอิงตรงกับ IndexFirstModel หน้าที่คุณสร้างขึ้น เช่น

หน้า/IndexFirst.cshtml.cs

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace CookieAuthenticationMultipleRazorPages.Pages
{
  [Authorize(AuthenticationSchemes = "FirstAuth")]
  public class IndexFirstModel : PageModel
  {
    private readonly ILogger<IndexFirstModel> _logger;

    public IndexFirstModel(ILogger<IndexFirstModel> logger)
    {
      _logger = logger;
    }

    public void OnGet() { }
  }
}

ไม่มีการจัดการพิเศษเนื่องจากจะแสดงเท่านั้น แต่โปรดทราบว่าเราได้เพิ่มเป็นแอตทริบิวต์ของ Authorize ชื่อคลาส AuthenticationSchemes อาร์กิวเมนต์ถูกตั้งค่าเป็นชื่อ Schema ที่ระบุใน Program.cs สิ่งนี้ทําให้มั่นใจได้ว่าคุณสามารถดูหน้านี้ได้ก็ต่อเมื่อคุณเข้าสู่ระบบด้วยชื่อสคีมานี้เท่านั้น หากคุณเยี่ยมชมหน้านี้โดยไม่เข้าสู่ระบบ คุณจะถูกนําไปยังหน้าเข้าสู่ระบบ

หน้า/IndexSecond.cshtml

นี่เป็นหน้าที่สองหลังจากเข้าสู่ระบบ

@page
@model IndexSecondModel
@{
  ViewData["Title"] = "Second page";
}

<div class="text-center">
  <h1 class="display-4">Second Page</h1>
</div>

หน้า/IndexSecond.cshtml.cs

โปรดทราบว่ารหัสโดยพื้นฐานแล้วจะเหมือนกับหน้าเข้าสู่ระบบแรก แต่ชื่อสคีมาจะแตกต่างกัน

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc.RazorPages;

namespace CookieAuthenticationMultipleRazorPages.Pages
{
  [Authorize(AuthenticationSchemes = "SecondAuth")]
  public class IndexSecondModel : PageModel
  {
    private readonly ILogger<IndexSecondModel> _logger;

    public IndexSecondModel(ILogger<IndexSecondModel> logger)
    {
      _logger = logger;
    }

    public void OnGet() { }
  }
}

การสร้างหน้าเข้าสู่ระบบ

สร้างหน้าเข้าสู่ระบบสองหน้า

หน้า/บัญชี/LoginFirst.cshtml.cs

ผนวกแอตทริบิวต์เพื่อให้คุณสามารถเข้าถึงได้โดยไม่ต้อง AllowAnonymous เข้าสู่ระบบ

using Microsoft.AspNetCore.Authentication;
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 CookieAuthenticationMultipleRazorPages.Pages.Account
{
  [AllowAnonymous]
  public class LoginFirstModel : PageModel
  {
  }
}

สร้างตัวแปรและบัญชีผู้ใช้จําลองเพื่อรับข้อมูลการเข้าสู่ระบบที่คุณป้อน

[AllowAnonymous]
public class LoginFirstModel : PageModel
{
  /// <summary>ユーザー名。</summary>
  [BindProperty]
  [Required]
  [DisplayName("ユーザー名")]
  public string UserName { get; set; } = "";

  /// <summary>パスワード。</summary>
  [BindProperty]
  [Required]
  [DataType(DataType.Password)]
  [DisplayName("パスワード")]
  public string Password { get; set; } = "";

  /// <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, "FirstAuth");
  var principal = new ClaimsPrincipal(identity);

  // 認証クッキーをレスポンスに追加
  await HttpContext.SignInAsync("FirstAuth", principal);

  // ログインが必要な画面にリダイレクトします
  return RedirectToPage("/IndexFirst");
}

ความแตกต่างจากการเข้าสู่ระบบเดียวคือมีการระบุชื่อสคีมาแต่ละชื่อ ตําแหน่งที่คุณระบุคือ ClaimsIdentity อาร์กิวเมนต์และอาร์กิว HttpContext.SignInAsync เมนต์ของ ที่นี่คุณสามารถระบุสคีมาที่คุณต้องการเข้าสู่ระบบด้วย

การออกจากระบบยังอยู่ในรูปแบบของการระบุชื่อสคีมา

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

หน้า/บัญชี/LoginFirst.cshtml

ด้านมุมมองไม่แตกต่างจากการเข้าสู่ระบบเพียงครั้งเดียว กรุณาให้ตรงกับชื่อรุ่นที่จะอ้างอิง

@page
@model LoginFirstModel
@{}

<p>Login1</p>

<form method="post">
  <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="/IndexFirst">認証が必要な画面へ直接リンク</a>
    </div>
  </div>
</form>

@section Scripts {
  @{
    await Html.RenderPartialAsync("_ValidationScriptsPartial");
  }
}

หน้า/บัญชี/LoginSecond.cshtml.cs

นี่คือตรรกะการเข้าสู่ระบบอื่น First Second มันแตกต่างกัน

using Microsoft.AspNetCore.Authentication;
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 CookieAuthenticationMultipleRazorPages.Pages.Account
{
  [AllowAnonymous]
  public class LoginSecondModel : PageModel
  {
    /// <summary>ユーザー名。</summary>
    [BindProperty]
    [Required]
    [DisplayName("ユーザー名")]
    public string UserName { get; set; } = "";

    /// <summary>パスワード。</summary>
    [BindProperty]
    [Required]
    [DataType(DataType.Password)]
    [DisplayName("パスワード")]
    public string Password { get; set; } = "";

    /// <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, "SecondAuth");
      var principal = new ClaimsPrincipal(identity);

      // 認証クッキーをレスポンスに追加
      await HttpContext.SignInAsync("SecondAuth", principal);

      // ログインが必要な画面にリダイレクトします
      return RedirectToPage("/IndexSecond");
    }

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

หน้า/บัญชี/LoginSecond.cshtml

ทิวทัศน์ First มันแค่นั้นและ Second แตกต่างกัน

@page
@model LoginSecondModel
@{}

<p>Login Second</p>

<form method="post">
  <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="/IndexSecond">認証が必要な画面へ直接リンク</a>
    </div>
  </div>
</form>

@section Scripts {
  @{
    await Html.RenderPartialAsync("_ValidationScriptsPartial");
  }
}

หน้า/แชร์/_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/LoginFirst" asp-page-handler="Logout">ログアウト(First)</a>
    </li>
    <li class="nav-item">
      <a class="nav-link text-dark" asp-page="/Account/LoginFirst">ログアウトせずログインへ(First)</a>
    </li>
    <li class="nav-item">
      <a class="nav-link text-dark" asp-page="/Account/LoginSecond" asp-page-handler="Logout">ログアウト(Second)</a>
    </li>
    <li class="nav-item">
      <a class="nav-link text-dark" asp-page="/Account/LoginSecond">ログアウトせずログインへ(Second)</a>
    </li>
    <li class="nav-item">
      <a class="nav-link text-dark" asp-page="/IndexFirst">IndexFirst</a>
    </li>
    <li class="nav-item">
      <a class="nav-link text-dark" asp-page="/IndexSecond">IndexSecond</a>
    </li>
    <!-- ここまで追加 -->
  </ul>
</div>
<!-- 中略 -->

โปรแกรมสําหรับโครงการ MVC

การสร้างรูปแบบการเข้าสู่ระบบ

คราวนี้ค่าอินพุตของหน้าจอเข้าสู่ระบบทั้งสองจะเหมือนกันดังนั้นเราจะแบ่งปันและสร้างเพียงค่าเดียว

using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace CookieAuthenticationMultipleMvc.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 ดังนั้นคุณต้องเพิ่มตัวควบคุมเพียงตัวเดียว

AllowAnonymous ระบุแหล่งที่มาเพื่อให้คุณสามารถเข้าถึงได้โดยไม่ต้องเข้าสู่ระบบ

using CookieAuthenticationMultipleMvc.Models;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using System.Security.Claims;

namespace CookieAuthenticationMultipleMvc.Controllers
{
  /// <remarks>
  /// <see cref="AllowAnonymous"/> 属性は Cookie 認証していなくてもアクセスできる Action (Controller) であることを示す。
  /// </remarks>
  [AllowAnonymous]
  public class AccountController : Controller
  {
  }
}

สร้างบัญชีผู้ใช้จําลอง

[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 LoginFirst() => View();

ด้านล่างนี้คือรหัสที่ต้องดําเนินการเมื่อเข้าสู่ระบบ

/// <summary>ログイン処理を実行します。</summary>
[HttpPost]
public async Task<IActionResult> LoginFirst(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, "FirstAuth");
  var principal = new ClaimsPrincipal(identity);

  // 認証クッキーをレスポンスに追加
  await HttpContext.SignInAsync("FirstAuth", principal);

  // ログインが必要な画面にリダイレクトします
  return RedirectToAction(nameof(HomeController.Index), "HomeFirst");
}

ความแตกต่างจากการเข้าสู่ระบบเดียวคือมีการระบุชื่อสคีมาแต่ละชื่อ ตําแหน่งที่คุณระบุคือ ClaimsIdentity อาร์กิวเมนต์และอาร์กิว HttpContext.SignInAsync เมนต์ของ ที่นี่คุณสามารถระบุสคีมาที่คุณต้องการเข้าสู่ระบบด้วย

การออกจากระบบยังอยู่ในรูปแบบของการระบุชื่อสคีมา

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

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

ฉันจะเพิ่มการเข้าสู่ระบบครั้งที่สองด้วย Firstไม่มีความแตกต่างอื่น ๆ เพียงแค่เปลี่ยนส่วนของSecond

// 中略

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

/// <summary>ログイン処理を実行します。</summary>
[HttpPost]
public async Task<IActionResult> LoginSecond(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, "SecondAuth");
  var principal = new ClaimsPrincipal(identity);

  // 認証クッキーをレスポンスに追加
  await HttpContext.SignInAsync("SecondAuth", principal);

  // ログインが必要な画面にリダイレクトします
  return RedirectToAction(nameof(HomeController.Index), "HomeSecond");
}

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

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

// 中略

การสร้างมุมมอง (แบบฟอร์มเข้าสู่ระบบ)

สร้างมุมมองละสองมุมมอง

ไม่มีความแตกต่างมากนักระหว่างการเข้าสู่ระบบครั้งเดียวและรหัส ดังนั้นฉันจะโพสต์รหัสตามที่เป็นอยู่

มุมมอง/บัญชี/LoginFirst.cshtml

@model LoginModel
@{}

<h1>Login First</h1>

<form asp-action="LoginFirst">
  <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="HomeFirst" asp-action="Index">認証が必要な画面へ直接リンク</a>
    </div>
  </div>
</form>

@section Scripts {
  @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}

มุมมอง/บัญชี/LoginSecond.cshtml

@model LoginModel
@{}

<h1>Login Second</h1>

<form asp-action="LoginSecond">
  <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="HomeSecond" asp-action="Index">認証が必要な画面へ直接リンク</a>
    </div>
  </div>
</form>

@section Scripts {
  @{ await Html.RenderPartialAsync("_ValidationScriptsPartial"); }
}

การสร้างหน้าจอหลังจากเข้าสู่ระบบ

HomeControllerสร้างคอนโทรลเลอร์ใหม่สองตัวโดยไม่ต้องใช้คอนโทรลเลอร์ที่มีอยู่ นี่คือตัวควบคุมที่คุณสามารถเข้าถึงได้หลังจากเข้าสู่ระบบ แต่ละหน้าจอถูกตั้งค่าให้สามารถเข้าถึงได้แตกต่างกันไปขึ้นอยู่กับหน้าจอที่คุณเข้าสู่ระบบ

หน้าหลัก FirstController.cs

เนื่องจากแสดงเฉพาะหน้าจอจึงไม่มีอะไรเพิ่มการประมวลผล

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace CookieAuthenticationMultipleMvc.Controllers
{
  [Authorize(AuthenticationSchemes = "FirstAuth")]
  public class HomeFirstController : Controller
  {
    public IActionResult Index() => View();
  }
}

แต่จะแนบแอตทริบิวต์กับคอนโทรลเลอร์และAuthenticationSchemesระบุชื่อสคีมาเป็นAuthorizeอาร์กิวเมนต์แทน FirstAuthสิ่งนี้ทําให้มั่นใจได้ว่าคุณสามารถเข้าถึงคอนโทรลเลอร์นี้ได้ก็ต่อเมื่อคุณตรวจสอบสิทธิ์ด้วยสคีมาเท่านั้น

หน้าหลัก SecondController.cs

Second สร้างด้านข้างในลักษณะเดียวกัน

using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;

namespace CookieAuthenticationMultipleMvc.Controllers
{
  [Authorize(AuthenticationSchemes = "SecondAuth")]
  public class HomeSecondController : Controller
  {
    public IActionResult Index() => View();
  }
}

มุมมอง/HomeFirst/Index.cshtml

ไม่มีอะไรยากเป็นพิเศษเพราะมันเพิ่งแสดง แยกแยะความแตกต่างเพื่อให้คุณเห็นว่าเป็นหน้าใด

@{
  ViewData["Title"] = "First View";
}

<div class="text-center">
  <h1 class="display-4">First View</h1>
</div>

มุมมอง/HomeSecond/Index.cshtml

เพียงแค่แสดงที่นี่เช่นกัน

@{
  ViewData["Title"] = "Second View";
}

<div class="text-center">
  <h1 class="display-4">Second View</h1>
</div>

มุมมอง/แชร์/_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-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="LogoutFirst">ログアウト(First)</a>
    </li>
    <li class="nav-item">
      <a class="nav-link text-dark" asp-controller="Account" asp-action="LoginFirst">ログアウトせずログインへ(First)</a>
    </li>
    <li class="nav-item">
      <a class="nav-link text-dark" asp-controller="Account" asp-action="LogoutSecond">ログアウト(Second)</a>
    </li>
    <li class="nav-item">
      <a class="nav-link text-dark" asp-controller="Account" asp-action="LoginSecond">ログアウトせずログインへ(Second)</a>
    </li>
    <li class="nav-item">
      <a class="nav-link text-dark" asp-controller="HomeFirst" asp-action="Index">IndexFirst</a>
    </li>
    <li class="nav-item">
      <a class="nav-link text-dark" asp-controller="HomeSecond" asp-action="Index">IndexSecond</a>
    </li>
    <!-- ここまで追加 -->
  </ul>
</div>
<!-- 中略 -->

การยืนยันการดําเนินการ

โปรดเรียกใช้เพื่อดูว่ามันทํางานอย่างไร ฉันแน่ใจว่าคุณเคยเห็นงานเข้าสู่ระบบเดียวแล้ว ดังนั้น ฉันคิดว่าเป็นความคิดที่ดีที่จะตรวจสอบว่าจะเกิดอะไรขึ้นเมื่อคุณเข้าถึงแต่ละหน้าจอเมื่อคุณรักษาสถานะการเข้าสู่ระบบในรูปแบบต่อไปนี้

  • ไม่มีการเข้าสู่ระบบครั้งแรกและครั้งที่สอง
  • ครั้งแรกเข้าสู่ระบบและที่สองไม่ได้เข้าสู่ระบบ
  • ครั้งแรกไม่ได้เข้าสู่ระบบ ที่สองเข้าสู่ระบบ
  • เข้าสู่ระบบทั้งที่หนึ่งและสอง