쿠키 인증을 사용하여 로그인 메커니즘을 만들고, 인증되지 않은 경우 리디렉션할 메커니즘을 만듭니다.

페이지 업데이트 :
페이지 생성 날짜 :

운영 환경

비주얼 스튜디오
  • Visual Studio 커뮤니티 2022
ASP.NET Core(MVC, Razor 페이지)
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의 경우 ASP.NET Core Web App(Model-View-Controller)을 선택합니다.

선택한 프로젝트 이름과 프로젝트 위치를 지정합니다.

인증 유형으로 "None(없음)"을 선택합니다. 다른 인증을 선택하는 경우 ASP.NET 코어 ID를 사용합니다. 설정이 완료되면 "만들기" 버튼을 클릭합니다.

프로젝트 생성 후 디버깅 실행 시 아래와 같은 화면이 표시됩니다. 이 화면을 기반으로 프로그램을 만듭니다.

Program>편집:.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 쿠키 인증은 and 메소드를 실행하여 활성화할 수 있습니다. 체계 이름을 CookieAuthenticationDefaults.AuthenticationScheme 변경할 필요가 없으면 을 지정합니다.

AddAuthorizationoptions.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 프로젝트용 프로그램

로그인 페이지 만들기(Pages/Account/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 메서드를 호출하면 쿠키를 삭제하고 로그인하지 않은 상태로 되돌릴 수 있습니다.

보기 만들기

우리는 외모를 고려하지 않습니다. 아래와 같이 사용자 이름과 비밀번호를 입력하기 위한 필드를 추가하고 로그인 버튼을 배치합니다. 테스트를 위해 /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"으로 설정되어 있기 때문입니다. 이 경로를 변경하려는 경우 Program.cs 메서드의 옵션 AddCookie 에서 변경할 수 있습니다. 지금은 기본 설정으로 진행하겠습니다.

먼저 컨트롤러 쪽을 만들어 보겠습니다.

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 메서드를 호출하면 쿠키를 삭제하고 로그인하지 않은 상태로 되돌릴 수 있습니다.

보기(로그인 양식) 만들기(/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 코드는 여기까지입니다.

작동 확인

이것으로 쿠키 인증에 필요한 최소 구현이 완료됩니다. 그것을 실행하고 어떻게 작동하는지 확인하십시오. 동작은 로그인 여부에 따라 변경되어야 합니다. 간단한 예로, 다음과 같은 동작을 볼 수 있습니다.

조작 연산 결과
로그인하지 않고 집에 가기 로그인 화면으로 리디렉션
로그인 홈 화면으로 이동
집에서 로그아웃하고 로그인하지 않고 집에 가십시오. 로그인 화면으로 리디렉션
집에서 로그아웃하고 로그인하지 않고 집에 가기 홈 화면으로 이동