ASP.NET Core Identity

  • 17 minutes to read

ASP.NET Core Identity는 사용자 인증 및 권한 부여를 위한 API를 제공하는, Microsoft의 ASP.NET Core 프레임워크용 보안 시스템입니다.

ASP.NET Core Identity의 클레임(Claim) 이해하기

ASP.NET Core Identity에서 "클레임(Claim)"은 사용자의 신원 정보나 권한과 같은 속성을 나타내는 중요한 구성 요소입니다. 기본적으로, 클레임은 사용자에 관한 정보나 권한을 나타내는 키와 값의 쌍으로 이루어져 있습니다. 이러한 클레임은 사용자의 인증 정보와 권한을 관리하는 데 필수적입니다.

영어로 'Claim'은 "주장" 또는 "청구"라는 의미를 가지나, 보안 및 인증 컨텍스트에서는 위와 같이 사용자의 신원 정보를 의미하는 특별한 용어로 쓰입니다.

ASP.NET Core Identity의 SQL 테이블 설명

ASP.NET Core Security Features

  • Authentication: 사용자가 누구인지 확인하는 프로세스.
  • Authorization: 특정 리소스에 대한 액세스를 제어하는 프로세스.
  • Data protection: 앱 내의 중요 데이터를 보호합니다.
  • HTTPS enforcement: 안전한 통신을 보장합니다.
  • App secrets: 개발 중 중요 정보를 안전하게 저장합니다.
  • Anti-request forgery protection: 웹사이트의 악의적 사용을 방지합니다.
  • CORS management: 다른 도메인의 리소스를 안전하게 사용할 수 있게 합니다.

ASP.NET Core Identity 기능

  • 로그인:
    • 로그인 처리: await _signInManager.PasswordSignInAsync(E, P, R, lockoutOnFailure: true);
    • 로그인 확인: SignInManager.IsSignedIn(User) 사용하여 현재 로그인 상태 확인.
    • 로그인한 사용자 이름 표시: @User.Identity.Name.
  • 로그아웃:
    • 사용자 로그아웃 처리: await _signInManager.SignOutAsync();

회원 관리

  • 회원 가입: _userManager.CreateAsync(user, Input.Password);을 사용하여 새 사용자 등록.
  • 회원 정보 확인: User.Identity.Name을 사용하여 현재 로그인한 사용자의 이름 표시.
  • 회원가입 코드 조각:
    var user = new IdentityUser { UserName = model.Email, Email = model.Email };
    var result = await _userManager.CreateAsync(user, model.Password);
    if (result.Succeeded)
    {
        // 회원 가입 성공 로직
    }
    
  • 회원정보 읽어오기: UserManager.FindByNameAsync() 메서드를 사용하여 사용자 정보 검색.

역할 및 권한 관리

  • User.IsInRole() 메서드로 역할 체크: 사용자가 특정 역할(예: "Administrators")에 속하는지 확인.
    @if (SignInManager.IsSignedIn(User) && User.IsInRole("Administrators"))
    {
        <a href="/Dashboard">Dashboard</a>
    }
    

ASP.NET Core Identity 구조

  • Stores: 사용자 및 역할 저장소 (IUserStore, IRoleStore).
  • Managers: 사용자 및 역할 관리 (UserManager, RoleManager).
  • Extensions: 추가 기능 및 유틸리티 (SignInManager, SecurityStamp, Validator).
  • Entity: 사용자 및 역할 모델 (User, Role).

ASP.NET Identity 패키지

  • Microsoft.Extensions.Identity.Core
  • Microsoft.AspNetCore.Identity
  • Microsoft.Extensions.Identity.Stores
  • Microsoft.AspNetCore.Identity.EntityFrameworkCore

ASP.NET Core Identity Providers

  • 내장: ASP.NET Core Identity 기본 제공.
  • 외부: Facebook, Google, GitHub 등 외부 공급자.

Identity UI 구성 요소

  • AccountManage 폴더: 로그인, 로그아웃, 회원가입, 비밀번호 재설정 등의 사용자 인터페이스를 관리합니다.
  • Shared 폴더: 사이트 전체에서 공유되는 부분 뷰와 레이아웃을 포함합니다.

ASP.NET Core Identity를 Hawaso.Identity 프로젝트에 적용하기

다음 패키지 관리자 콘솔 명령어를 사용하여 Hawaso.Identity 프로젝트에 ASP.NET Core Identity를 적용합니다. 각 패키지는 프로젝트의 보안과 데이터 관리 기능을 강화하는 데 필요한 요소를 제공합니다.

PM> Install-Package Microsoft.Extensions.Identity.Core // ASP.NET Core Identity의 핵심 기능을 제공합니다.
PM> Install-Package Dapper // 데이터베이스 쿼리와 작업을 간소화하는 ORM입니다.
PM> Install-Package Dul // 데이터 유틸리티 라이브러리, 다양한 유틸리티 기능을 제공합니다.
PM> Install-Package System.Configuration.ConfigurationManager // 구성 파일 관리와 액세스를 위한 클래스를 제공합니다.

이러한 패키지를 설치함으로써, 사용자 인증 및 관리, 데이터 액세스 및 처리, 그리고 애플리케이션 구성 관리에 필요한 기능을 프로젝트에 통합할 수 있습니다.

실습 및 데모

  • Role 기반 권한 설정 데모: 역할 기반으로 사용자의 권한을 설정하는 방법을 보여주는 간단한 데모.
  • GitHub 경로: 실습 코드와 예제 프로젝트가 포함된 GitHub 저장소.

데이터베이스 구조 및 설정

  • Roles 테이블: 역할(그룹) 정보를 저장합니다.
  • 사용자 계정 생성 및 역할 할당: 사용자 계정을 생성하고 역할을 할당하는 과정 설명.

VisualAcademy 프로젝트 적용

  • 인증 관련 모든 소스 포함: 인증과 관련된 기본 템플릿 및 페이지 포함.
  • ApplicationUser 및 ApplicationRole 클래스: 역할 기반 인증을 위한 사용자 및 역할 클래스.

[동영상 강의] 초간단 Role 기반 권한 설정 데모

이 동영상 강의에서는 ASP.NET Core Identity를 사용하여 역할 기반 권한을 설정하는 방법을 단계별로 설명합니다. 강의는 VisualAcademy GitHub의 BlazorRoleBasedAuthorization 프로젝트를 기반으로 진행됩니다.

프로젝트 설정 및 초기화

  1. 프로젝트 생성: 먼저 AspNetCoreIdentity 빈 솔루션에 'BlazorRoleBasedAuthorization' 이름으로 Blazor Server 프로젝트를 생성합니다.
  2. 초기 설정: 'Startup.cs' 파일에 필요한 구성 및 미들웨어를 추가합니다. 이는 권한 부여 및 인증 기능을 활성화하는 데 필요합니다. Starup.cs
  3. 역할 기반 페이지 생성:
    • 'Pages/RoleBasedAuthorization/AdministratorsOnly.razor': 관리자만 액세스할 수 있는 페이지를 구성합니다. AdministratorsOnly
    • 'Pages/RoleBasedAuthorization/UsersOver.razor': 특정 연령 이상의 사용자만 액세스할 수 있는 페이지를 구성합니다. UsersOver

데이터베이스 및 역할 설정

  1. Roles 테이블 설정: 데이터베이스의 'Roles' 테이블에 두 개의 역할(그룹)을 추가합니다. Roles
  2. 사용자 등록: 'Register' 페이지를 통해 'a@a.com'과 'b@b.com' 계정을 생성합니다. Register
  3. 역할 할당: 생성된 각 계정에 적절한 역할을 할당합니다. Add Roles

VisualAcademy 프로젝트 통합

VisualAcademy 프로젝트에는 인증 관련 모든 기본 템플릿과 페이지가 포함됩니다. 이 프로젝트는 'ApplicationUser.cs' 및 'ApplicationRole.cs' 클래스를 사용하여 역할 기반 인증을 수행하는 방식으로 변경되었습니다. 모든 스캐폴딩 파일들 포함

실습

  1. ASP.NET Core Identity가 포함된 웹 프로젝트 생성: 학습자는 직접 ASP.NET Core Identity를 포함하는 웹 프로젝트를 생성하고 구성하는 방법을 배웁니다.
  2. 스캐폴드 항목 추가: 학습자는 스캐폴드된 회원가입, 로그인, 로그아웃 페이지 및 기본 코드를 탐색하며 실습합니다.

SignInManager와 UserManager 활용

  • SignInManager:
    • .PasswordSignInAsync(): 사용자 로그인 처리.
    • .SignInAsync(): 로그인 처리 후 사용자 세션을 관리합니다.
  • UserManager:
    • .CreateAsync(): 새 사용자를 생성하고 데이터베이스에 저장합니다.

Identity 설정

  • IdentityOptions 클래스: 아이덴터티 시스템의 다양한 옵션을 설정하여 보안 및 사용성을 개선할 수 있습니다.

IdentityOptions 클래스 사용에 대한 아티클을 다음 링크를 참고하세요.

ASP.NET Core IdentityOptions 설정을 통한 보안 강화

8 [실습] ASP.NET Core Identity가 포함된 웹 프로젝트 생성

이 실습에서는 ASP.NET Core Identity를 포함하는 새로운 웹 프로젝트를 생성하는 과정을 안내합니다. 이를 통해 사용자 인증 및 권한 관리 시스템을 구축하는 기초를 마련할 수 있습니다.

9 [실습] 스캐폴드 항목 추가

이 부분에서는 기본 제공되는 회원가입, 로그인, 로그아웃 등의 기능을 스캐폴드하여 프로젝트에 추가하는 방법을 배웁니다. 스캐폴딩을 통해 자동 생성된 코드를 탐험하고 이해하면서 ASP.NET Core Identity의 작동 방식을 학습할 수 있습니다.

[실습] 회원가입, 로그인, 로그아웃 기본 코드 탐험

  • Register: 새 사용자를 시스템에 등록합니다.
  • Login: 등록된 사용자가 시스템에 로그인합니다.
  • Logout: 사용자가 시스템에서 로그아웃합니다.

SignInManager와 UserManager

  • SignInManager.PasswordSignInAsync(): 사용자 이름과 비밀번호를 사용하여 로그인 처리를 수행합니다.
  • SignInManager.SignInAsync(): 사용자를 로그인 시키고, 쿠키를 설정합니다.
  • UserManager.CreateAsync(): 새 사용자 계정을 생성하고 데이터베이스에 저장합니다.

IdentityOptions 클래스로 아이덴터티 설정

IdentityOptions 클래스를 사용하여 애플리케이션의 보안, 비밀번호 정책, 로그인 및 로그아웃 동작 등을 구성할 수 있습니다.

IdentityUser를 확장하는 ApplicationUser

ApplicationUser 클래스를 사용하여 기본 IdentityUser에 추가적인 프로필 데이터를 정의합니다.

코드: ApplicationUser.cs

using Microsoft.AspNetCore.Identity;

namespace VisualAcademy.Models
{
    // Add profile data for application users by adding properties to the ApplicationUser class
    public class ApplicationUser : IdentityUser
    {
        /// <summary>
        /// 주소
        /// </summary>
        public string Address { get; set; }

        /// <summary>
        /// 성별
        /// </summary>
        public string Gender { get; set; }
    }
}

서비스 추가:

Services.AddIdentity<ApplicationUser, IdentityRole>()

데이터베이스 마이그레이션:

Add-Migration AddColumn
Update-Database

SignInManager 인젝션 변경:

@inject SignInManager<IdentityUser> SignInManager
-To-
@inject SignInManager<ApplicationUser> SignInManager

엔터티 형식들

ASP.NET Core Identity 시스템에서 사용되는 주요 엔터티 형식들:

  • User
  • Role
  • UserClaim
  • UserToken
  • UserLogin
  • RoleClaim
  • UserRole

외부 공급자

ASP.NET Core Identity는 Google, Facebook, Twitter 등과 같은 외부 공급자를 사용한 인증을 지원합니다.

CookieAuthenticationOptions

  • Domain: 쿠키가 연결된 도메인을 지정합니다.
  • Expiration: 쿠키의 만료 시간을 설정합니다.
  • ExpireTimeSpan: 쿠키의 생명 주기를 설정합니다.
  • Name: 쿠키의 이름을 설정합니다.

Identity UI

Identity UI는 사용자 인증과 관련된 일련의 Razor 페이지로 구성되며, Account 및 Manage 폴더에서 관리합니다. 각 폴더는 로그인, 로그아웃, 회원가입, 이메일 확인, 비밀번호 재설정 등 사용자의 인증 관련 활동을 처리하는 다양한 페이지를 포함합니다.

Identity UI 페이지 제목 목록

Account 폴더

Account 폴더에는 접근 거부 페이지, 이메일 확인 페이지, 외부 로그인 페이지 등 사용자의 계정 관련 활동을 처리하는 페이지들이 포함됩니다.

Manage 폴더

Manage 폴더에는 비밀번호 변경, 개인 데이터 삭제, 2단계 인증 관리 등 사용자의 계정 설정을 관리하는 페이지들이 포함됩니다.

Shared 폴더

Shared 폴더에는 로그인 상태를 표시하는 로그인 부분 뷰(_LoginPartial.cshtml) 등 여러 페이지에서 공통적으로 사용되는 부분 뷰들이 포함됩니다.

이 문서는 ASP.NET Core Identity를 사용하여 인증 시스템을 구축하고 관리하는 과정을 체계적으로 이해하고 실습할 수 있는 기본 지침서 역할을 합니다. 사용자 인증 및 권한 관리에 대한 깊이 있는 이해를 돕기 위해 제공된 내용을 차근차근 따라가며 학습하시길 바랍니다.

UserController.cs

UserController.cs는 사용자 관리를 위한 컨트롤러 파일로, 사용자 생성, 수정, 삭제 등 사용자 관련 기능을 처리하는 엔드포인트들을 포함합니다.

Identity UI

├─Account │ │ AccessDenied.cshtml │ │ AccessDenied.cshtml.cs │ │ ConfirmEmail.cshtml │ │ ConfirmEmail.cshtml.cs │ │ ConfirmEmailChange.cshtml │ │ ConfirmEmailChange.cshtml.cs │ │ ExternalLogin.cshtml │ │ ExternalLogin.cshtml.cs │ │ ForgotPassword.cshtml │ │ ForgotPassword.cshtml.cs │ │ ForgotPasswordConfirmation.cshtml │ │ ForgotPasswordConfirmation.cshtml.cs │ │ Lockout.cshtml │ │ Lockout.cshtml.cs │ │ Login.cshtml │ │ Login.cshtml.cs │ │ LoginWith2fa.cshtml │ │ LoginWith2fa.cshtml.cs │ │ LoginWithRecoveryCode.cshtml │ │ LoginWithRecoveryCode.cshtml.cs │ │ Logout.cshtml │ │ Logout.cshtml.cs │ │ LogOutBlazor.cshtml │ │ Register.cshtml │ │ Register.cshtml.cs │ │ RegisterConfirmation.cshtml │ │ RegisterConfirmation.cshtml.cs │ │ ResendEmailConfirmation.cshtml │ │ ResendEmailConfirmation.cshtml.cs │ │ ResetPassword.cshtml │ │ ResetPassword.cshtml.cs │ │ ResetPasswordConfirmation.cshtml │ │ ResetPasswordConfirmation.cshtml.cs │ │ SetPassword.cshtml # 사용자 정의 │ │ SetPassword.cshtml.cs │ │ SetPasswordConfirmation.cshtml # 사용자 정의 │ │ SetPasswordConfirmation.cshtml.cs │ │ _StatusMessage.cshtml │ │ _ViewImports.cshtml │ │ │ └─Manage │ ChangePassword.cshtml │ ChangePassword.cshtml.cs │ DeletePersonalData.cshtml │ DeletePersonalData.cshtml.cs │ Disable2fa.cshtml │ Disable2fa.cshtml.cs │ DownloadPersonalData.cshtml │ DownloadPersonalData.cshtml.cs │ Email.cshtml │ Email.cshtml.cs │ EnableAuthenticator.cshtml │ EnableAuthenticator.cshtml.cs │ ExternalLogins.cshtml │ ExternalLogins.cshtml.cs │ GenerateRecoveryCodes.cshtml │ GenerateRecoveryCodes.cshtml.cs │ Index.cshtml │ Index.cshtml.cs │ ManageNavPages.cs │ PersonalData.cshtml │ PersonalData.cshtml.cs │ ResetAuthenticator.cshtml │ ResetAuthenticator.cshtml.cs │ SetPassword.cshtml │ SetPassword.cshtml.cs │ ShowRecoveryCodes.cshtml │ ShowRecoveryCodes.cshtml.cs │ TwoFactorAuthentication.cshtml │ TwoFactorAuthentication.cshtml.cs │ _Layout.cshtml │ _ManageNav.cshtml │ _StatusMessage.cshtml │ _ViewImports.cshtml │ _ViewStart.cshtml │ └─Shared _LoginPartial.cshtml

페이지들

SetPassword.cshtml - 초기 암호 설정 페이지

이 페이지는 사용자가 처음으로 자신의 암호를 설정할 수 있는 인터페이스를 제공합니다. 사용자가 이메일을 통해 받은 코드를 사용하여 이 페이지에 접근하며, 여기서 새 암호를 생성할 수 있습니다.

Code: \Areas\Identity\Pages\Account\SetPassword.cshtml

@page
@model InitialPasswordModel
@{
    ViewData["Title"] = "Set password";
}

<h1>@ViewData["Title"]</h1>
<h4>Set your password.</h4>
<hr />
<div class="row">
    <div class="col-md-4">
        <form method="post">
            <div asp-validation-summary="ModelOnly" class="text-danger"></div>
            <input asp-for="Input.Code" type="hidden" />
            <div class="form-group">
                <label asp-for="Input.Email"></label>
                <input asp-for="Input.Email" class="form-control" />
                <span asp-validation-for="Input.Email" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Input.Password"></label>
                <input asp-for="Input.Password" class="form-control" />
                <span asp-validation-for="Input.Password" class="text-danger"></span>
            </div>
            <div class="form-group">
                <label asp-for="Input.ConfirmPassword"></label>
                <input asp-for="Input.ConfirmPassword" class="form-control" />
                <span asp-validation-for="Input.ConfirmPassword" class="text-danger"></span>
            </div>
            <button type="submit" class="btn btn-primary">Reset</button>
        </form>
    </div>
</div>

@section Scripts {
    <partial name="_ValidationScriptsPartial" />
}

Code: \Areas\Identity\Pages\Account\SetPassword.cshtml.cs

#nullable disable
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.AspNetCore.WebUtilities;
using System.ComponentModel.DataAnnotations;
using System.Text;
using VisualAcademy.Areas.Identity.Models;

namespace VisualAcademy.Areas.Identity.Pages.Account
{
    [AllowAnonymous]
    public class InitialPasswordModel : PageModel
    {
        private readonly UserManager<ApplicationUser> _userManager;
        private readonly SignInManager<ApplicationUser> _signInManager;

        public InitialPasswordModel(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)
        {
            _userManager = userManager;
            _signInManager = signInManager;
        }

        [BindProperty]
        public InputModel Input { get; set; }

        public class InputModel
        {
            [Required]
            [EmailAddress]
            public string Email { get; set; }

            [Required]
            [DataType(DataType.Password)]
            public string Password { get; set; }

            [DataType(DataType.Password)]
            [Display(Name = "Confirm password")]
            [Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
            public string ConfirmPassword { get; set; }

            public string Code { get; set; }

            public string Code1 { get; set; }
        }

        public async Task<IActionResult> OnGetAsync(string code = null, string code1 = null)
        {
            await _signInManager.SignOutAsync();
            if (code == null)
            {
                return BadRequest("A code must be supplied for password reset.");
            }
            else
            {
                Input = new InputModel
                {
                    Code = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code)),
                    Code1 = Encoding.UTF8.GetString(WebEncoders.Base64UrlDecode(code1)),
                };
                return Page();
            }
        }

        public async Task<IActionResult> OnPostAsync()
        {
            if (!ModelState.IsValid)
            {
                return Page();
            }

            var user = await _userManager.FindByEmailAsync(Input.Email);
            if (user == null)
            {
                // Don't reveal that the user does not exist
                return RedirectToPage("./SetPasswordConfirmation");
            }

            var result = await _userManager.ResetPasswordAsync(user, Input.Code, Input.Password);
            IdentityResult emailConfirmed = new();
            if (result.Succeeded)
            {
                user.EmailConfirmed = true;
                await _userManager.UpdateAsync(user);

                return RedirectToPage("./SetPasswordConfirmation");
            }

            foreach (var error in result.Errors.Concat(emailConfirmed.Errors))
            {
                ModelState.AddModelError(string.Empty, error.Description);
            }
            return Page();
        }
    }
}

SetPasswordConfirmation.cshtml - 암호 설정 확인 페이지

사용자가 암호를 성공적으로 설정한 후에 이 페이지로 리디렉션됩니다. 이 페이지는 사용자에게 암호 설정이 완료되었음을 알리고, 로그인 페이지로 넘어갈 수 있는 링크를 제공합니다.

Code: \Areas\Identity\Pages\Account\SetPasswordConfirmation.cshtml

@page
@model SetPasswordConfirmationModel
@{
    ViewData["Title"] = "Password confirmation";
}

<h1>@ViewData["Title"]</h1>
<p>
    Your password has been set. Please <a asp-page="./Login">click here to log in</a>.
</p>

Code: \Areas\Identity\Pages\Account\setPasswordConfirmation.cshtml.cs

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

namespace VisualAcademy.Areas.Identity.Pages.Account
{
    [AllowAnonymous]
    public class SetPasswordConfirmationModel : PageModel
    {
        public void OnGet()
        {
        }
    }
}
VisualAcademy Docs의 모든 콘텐츠, 이미지, 동영상의 저작권은 박용준에게 있습니다. 저작권법에 의해 보호를 받는 저작물이므로 무단 전재와 복제를 금합니다. 사이트의 콘텐츠를 복제하여 블로그, 웹사이트 등에 게시할 수 없습니다. 단, 링크와 SNS 공유, Youtube 동영상 공유는 허용합니다. www.VisualAcademy.com
박용준 강사의 모든 동영상 강의는 데브렉에서 독점으로 제공됩니다. www.devlec.com