ASP.NET Identity의 개요

등록일시: 2014-06-12 08:00,  수정일시: 2015-07-25 13:42
조회수: 11,020
이 문서는 ASP.NET Identity 기술을 널리 알리고자 하는 개인적인 취지로 제공되는 번역문서입니다. 이 문서에 대한 모든 저작권은 마이크로소프트에 있으며 요청이 있을 경우 언제라도 게시가 중단될 수 있습니다. 번역 내용에 오역이 존재할 수 있고 주석은 번역자 개인의 의견일 뿐이며 마이크로소프트는 이에 관한 어떠한 보장도 하지 않습니다. 번역이 완료된 이후에도 대상 제품 및 기술이 개선되거나 변경됨에 따라 원문의 내용도 변경되거나 보완되었을 수 있으므로 주의하시기 바랍니다.

ASP.NET의 멤버십 시스템은 지난 2005년, ASP.NET 2.0과 함께 소개되었습니다. 그러나, 그 이후로도 웹 응용 프로그램에서 인증이나 권한 부여를 처리하는 보편적인 방식에는 많은 변화가 있었습니다. ASP.NET Identity는 웹이나 핸드폰, 태블릿 등을 위한 현대적인 응용 프로그램을 구축하기 위해서 필요한 멤버십 시스템의 새로운 모습입니다.

본문은 Pranav Rastogi (@rustd), Jon Galloway (@jongalloway), Tom Dykstra, 그리고 Rick Anderson (@RickAndMSFT)에 의해서 작성되었습니다.

배경지식: ASP.NET과 멤버십

ASP.NET 멤버십(ASP.NET Membership)

ASP.NET 멤버십은 사이트 멤버십에 대한 2005년 경의 보편적인 요구 사항들을 해결하기 위해서 설계되었으며, 일반적으로 사용자 이름과 비밀번호, 프로필 데이터를 저장하는 SQL Server 및 폼 인증을 통해서 구성됩니다. 그러나, 오늘날에는 웹 응용 프로그램을 지원하는 훨신 더 광범위한 데이터 저장 옵션들이 등장했을뿐만 아니라, 대부분의 개발자들이 소셜 신원 공급자들을 이용해서 자신의 사이트에 인증이나 권한 부여 기능을 구현하기를 원합니다. 그럼에도 불구하고 기존의 ASP.NET 멤버십 시스템은 다음과 같은 설계적 한계들로 인해서 이런 변화들을 수용하기가 매우 어렵습니다:

  • 데이터베이스 스키마 자체가 SQL Server를 대상으로 설계되어 있으며 수정이 불가능합니다. 프로필 정보를 추가할 수는 있지만 추가된 데이터는 별도의 테이블에 저장되므로, 프로필 공급자 API를 사용하지 않는 다른 방법으로는 프로필 정보에 일관적으로 접근하기가 어렵습니다.
  • 공급자 시스템을 이용해서 내부 데이터 저장소를 변경할 수는 있지만 시스템 자체가 관계형 데이터베이스에 적합한 전제조건들을 기반으로 설계되어 있습니다. 따라서, 멤버십 정보를 Windows Azure Storage Tables 같은 비-관계형 저장소 매카니즘에 저장하는 공급자를 작성할 수는 있지만, 관계형 설계를 우회하기 위해서는 많은 코드를 작성해야 할 뿐만 아니라, NoSQL 데이터베이스에 적용 불가능한 메서드들은 모두 System.NotImplementedException 예외를 던지도록 구현해야 합니다.
  • OWIN은 외부 신원 공급자들을 (Microsoft Accounts, Facebook, Google, Twitter 등) 이용한 로그인 지원이나, 온-프레미스 Active Directory 및 Windows Azure Active Directory의 조직 계정을 이용한 로그인 지원을 비롯해서, 인증을 지원하기 위한 다양한 미들웨어 구성 요소들을 포함하고 있습니다. 가령, OWIN은 OAuth 2.0과 JWT, 그리고 CORS까지도 지원해줍니다. 그러나, 멤버십 시스템의 로그인 기능과 로그아웃 기능은 폼 인증을 기반으로 구현되기 때문에 OWIN을 활용할 수가 없습니다.

ASP.NET 단순 멤버십(ASP.NET Simple Membership)

ASP.NET 단순 멤버십은 ASP.NET Web Pages를 위한 멤버십 시스템으로 개발되었으며, WebMatrix와 Visual Studio 2010 SP1과 함께 소개되었습니다. 단순 멤버십의 목표는 Web Pages 응용 프로그램에 손쉽게 멤버십 기능을 추가하는 것이었습니다.

단순 멤버십을 사용하면 사용자 프로필 정보를 비교적 손쉽게 재정의할 수는 있지만, 여전히 ASP.NET 멤버십이 갖고 있는 나머지 문제점들을 공유하고 있기 때문에 다음과 같은 몇 가지 한계를 갖고 있습니다:

  • 멤버십 시스템의 데이터를 비-관계형 저장소에 영속화하기가 어렵습니다.
  • OWIN과 함께 사용할 수 없습니다.
  • 기존 ASP.NET 멤버십 공급자들을 사용해서는 잘 동작하지 않으며 확장이 어렵습니다.

ASP.NET 범용 공급자(ASP.NET Universal Providers)

ASP.NET 범용 공급자는 Windows Azure SQL Database에 멤버십 정보를 저장하기 위한 용도로 개발되었으며, SQL Server Compact에서도 잘 동작합니다. 범용 공급자는 Entity Framework Code First를 기반으로 구축되었기 때문에 EF가 지원하기만 한다면 어떤 저장소에도 범용 공급자를 통해서 데이터를 저장할 수 있습니다. 범용 공급자를 사용하면 데이터베이스 스키마도 상당히 깔끔하게 정리할 수 있습니다.

그러나, 범용 공급자 역시 ASP.NET 멤버십 기반구조에 근거를 두고 만들어져 있기 때문에, 여전히 SqlMembership 공급자와 같은 제약 사항들을 갖고 있습니다. 다시 말해서, 관계형 데이터베이스를 대상으로 설계되었고 프로필이나 사용자 정보를 재정의하기도 매우 어렵습니다. 게다가 여전히 로그인 기능과 로그아웃 기능에 폼 인증을 사용합니다.

ASP.NET Identity

지난 몇 년간 변모해온 ASP.NET 멤버십의 변화 과정에서 알 수 있듯이, ASP.NET 팀은 고객들의 피드백으로부터 많은 것을 배웠습니다.

가령, 사용자들이 항상 여러분의 응용 프로그램에 등록했던 사용자 이름과 비밀번호를 입력해서 로그인 할 것이라는 예상은 더 이상 유효하지 않습니다. 웹은 더욱 사회적으로 바뀌었으며, 사용자들은 Facebook이나 Twitter 또는 그 밖의 다른 소셜 웹 사이트 같은 다양한 채널들을 통해서 서로 실시간으로 교감하고 있습니다. 개발자들은 그들의 웹 사이트에서 풍부한 경험을 제공할 수 있도록 사용자가 자신의 소셜 신원으로 로그인할 수 있게 만들고 싶어합니다. 결과적으로, 현대적인 멤버십 시스템은 Facebook이나 Twitter를 비롯한 인증 공급자에 대한 재지정-기반 로그인(Redirection-Based Log-ins)을 지원해야만 합니다.

또한, 웹 개발이 발전함에 따라 웹 개발의 패턴도 역시 발전했습니다. 단적으로 응용 프로그램의 코드에 대한 단위 테스트가 응용 프로그램 개발자들의 주요 관심사가 되었습니다. 2008년도에는 ASP.NET에 모델-뷰-컨트롤러(MVC, Model-View-Controller) 패턴에 기반한 새로운 프레임워크가 추가되어 개발자들이 단위 테스트가 가능한 ASP.NET 응용 프로그램을 구축할 수 있게 되었습니다. 당연한 얘기지만, 자신의 응용 프로그램 로직을 단위 테스트하고 싶어하는 개발자라면 멤버십 시스템에 대한 단위 테스트도 수행하고 싶을 것입니다.

이런 웹 응용 프로그램 개발의 변화를 고려해서 ASP.NET Identity는 다음과 같은 목표를 갖고 개발되었습니다:

  • 단일 ASP.NET Identity 시스템
    • ASP.NET Identity는 ASP.NET MVC, Web Forms, Web Pages, Web API, 그리고 SignalR 등 모든 ASP.NET 프레임워크에서 사용할 수 있습니다.
    • ASP.NET Identity는 웹, 핸드폰, 스토어 또는 하이브리드 응용 프로그램을 구축할 때도 사용 가능합니다.
  • 손쉬운 사용자 프로필 데이터의 연결
    • 사용자 및 프로필 정보에 대한 스키마를 직접 제어할 수 있습니다. 가령, 시스템을 간단하게 변경해서 응용 프로그램에 계정을 등록할 때 사용자로부터 입력 받은 생일을 저장할 수 있습니다.
  • 영속성 제어
    • 기본적으로 ASP.NET Identity 시스템은 모든 사용자 정보를 데이터베이스에 저장합니다. ASP.NET Identity는 모든 영속성 관련 메커니즘을 Entity Framework Code First를 통해서 구현하고 있습니다.
    • 직접 데이터베이스의 스키마를 제어할 수 있으므로 테이블 이름을 변경하거나 기본 키의 데이터 형식을 변경하는 등의 일반적인 작업을 간단하게 처리할 수 있습니다.
    • System.NotImplementedExceptions 예외를 던지지 않고도 SharePoint, Windows Azure Storage Table Service, NoSQL 데이터베이스 등의 다른 저장소 메커니즘을 손쉽게 연결할 수 있습니다.
  • 단위 테스트 용이성
    • ASP.NET Identity를 이용하면 단위 테스트하기에 보다 용이한 웹 응용 프로그래을 만들 수 있습니다. 즉, ASP.NET Identity를 사용하는 응용 프로그램의 코드에 대한 단위 테스트를 손쉽게 작성할 수 있습니다.
  • 역할 공급자
    • 역할을 이용해서 응용 프로그램의 각 부분들에 대한 접근을 통제할 수 있는 역할 공급자가 제공됩니다. 가령, "Admin" 같은 역할을 생성한 다음, 사용자를 쉽게 추가할 수 있습니다.
  • 클레임(Claims) 기반
    • ASP.NET Identity는 사용자의 신원을 클레임들의 모음으로 표현하는 클레임-기반 인증을 지원합니다. 개발자는 클레임들을 이용해서 역할을 사용할 때보다 훨씬 풍부하게 사용자의 신원을 기술할 수 있습니다. 역할 멤버십은 단지 여부만 표현할 수 있는 반면 (예, 멤버거나 아니거나) , 클레임은 사용자의 신원과 멤버십에 대한 더 다양한 정보들을 포함하고 있습니다.
  • 소셜 로그인 공급자
    • 응용 프로그램에 Microsoft Account, Facebook, Twitter, Google 등의 소셜 로그인 기능을 손쉽게 추가하고 사용자별 데이터를 저장할 수 있습니다.
  • Windows Azure Active Directory
    • 응용 프로그램에 Windows Azure Active Directory를 이용한 로그인 기능을 추가하고 사용자별 데이터를 저장할 수 있습니다. 더 많은 관련 정보는 Creating ASP.NET Web Projects in Visual Studio 2013 문서의 Organizational Accounts 절을 참고하시기 바랍니다.
  • OWIN 통합
    • ASP.NET 인증은 모든 유형의 OWIN 기반 호스트에서 사용할 수 있는 OWIN 미들웨어를 기반으로 합니다. 그리고, ASP.NET Identity는 System.Web에 대한 의존성을 전혀 갖고 있지 않습니다. OWIN 프레임워크를 완벽하게 준수하고 있으며 OWIN에서 호스팅되는 모든 응용 프로그램에서 사용할 수 있습니다.
    • ASP.NET Identity는 웹 사이트에서 사용자가 로그인하거나 로그아웃 할 때 OWIN 인증을 사용합니다. 이 얘기는 응용 프로그램이 쿠키를 생성하기 위해서 FormsAuthentication 클래스 대신, OWIN 쿠키 인증(OWIN Cookie Authentication)을 사용한다는 뜻입니다.
  • NuGet 패키지
    • ASP.NET Identity는 Visual Studio 2013에 포함된 ASP.NET MVC, Web Forms 및 Web API 템플릿에 설치할 수 있는 NuGet 패키지로 재배포됩니다. 이 NuGet 패키지는 NuGet 갤러리에서 다운로드 받을 수 있습니다.
    • 이처럼 ASP.NET Identity가 NuGet 패키지로 재배포되기 때문에, ASP.NET 팀이 손쉽게 신규 기능을 추가하거나 버그를 수정해서 반복적으로 기민하게 개발자들에게 재배포할 수 있습니다.

ASP.NET Identity 시작하기

ASP.NET Identity는 ASP.NET MVC, Web Forms, Web API, 그리고 SPA를 위한 Visual Studio 2013의 프로젝트 템플릿들에서 사용되고 있습니다. 본 자습서에서는 이 템플릿들에서 ASP.NET Identity로 사용자 등록, 로그인, 로그아웃 기능을 구현하고 있는 방법을 살펴봅니다.

ASP.NET Identity는 다음과 같은 과정들을 따라서 구현됩니다. 본 자습서의 목적은 ASP.NET Identity에 대한 전반적인 개념들을 소개하는데 있으며, 전체 과정을 한 단계씩 따라하거나 특정 단계의 세부 정보만 읽어봐도 무방합니다. ASP.NET Identity의 새로운 API들을 사용해서 사용자나 역할, 또는 프로필 정보를 추가하는 방법 등, 응용 프로그램 작성 방법에 대한 더 많은 정보들은 본문 후반부의 "후속 과정"절을 참고하시기 바랍니다.

  1. ASP.NET Identity는 ASP.NET MVC, Web Forms, Web API, SignalR 등에서 사용할 수 있으며, 본 자습서에서는 ASP.NET MVC 응용 프로그램을 이용해서 세부 내용들을 살펴보도록 하겠습니다. 먼저, 개별 사용자 계정(Individual Accounts) 옵션을 선택해서 새로운 ASP.NET MVC 응용 프로그램을 생성합니다.

  2. 생성된 프로젝트에는 다음과 같은 세 가지 ASP.NET Identity 관련 패키지들이 포함되게 됩니다. *
    • Microsoft.AspNet.Identity.EntityFramework
      이 패키지에는 ASP.NET Identity의 데이터와 스키마를 SQL Server에 영속화시키기 위한 ASP.NET Identity의 Entity Framework 구현이 담겨 있습니다.
    • Microsoft.AspNet.Identity.Core
      이 패키지에는 ASP.NET Identity에 대한 핵심 인터페이스들이 담겨 있습니다. 이 패키지는 Azure Table Storage, NoSQL 데이터베이스 등, 다른 영속화 저장소를 대상으로 하는 ASP.NET Identity의 구현을 작성할 때 사용됩니다.
    • Microsoft.AspNet.Identity.OWIN
      이 패키지에는 ASP.NET 응용 프로그램과 OWIN 인증을 이용한 ASP.NET Identity를 연결하기 위해 사용하는 기능들이 담겨 있습니다. 가령, 이 패키지는 응용 프로그램에 로그인 기능을 추가할 때, 쿠키를 생성하기 위해서 OWIN의 쿠키 인증 미들웨어를 호출할 때 사용됩니다.
  3. 사용자 추가하기
    응용 프로그램을 실행하고 사용자를 추가하기 위한 등록(Register) 링크를 클릭합니다. 다음 이미지는 사용자 이름(User name)과 암호(Password)를 수집하는 등록 페이지를 보여주고 있습니다. **

    이 페이지에서 사용자 정보를 입력하고 등록(Register) 버튼을 클릭하면, 다음과 같이 Account 컨트롤러의 Register 액션 메서드에서 ASP.NET Identity의 API가 호출되어 사용자가 생성됩니다:
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Register(RegisterViewModel model)
    {
        if (ModelState.IsValid)
        {
            var user = new ApplicationUser() { UserName = model.UserName };
            var result = await UserManager.CreateAsync(user, model.Password);
            if (result.Succeeded)
            {
                await SignInAsync(user, isPersistent: false);
                return RedirectToAction("Index", "Home");
            }
            else
            {
                AddErrors(result);
            }
        }
    
        // If we got this far, something failed, redisplay form
        return View(model);
    }
  4. 로그인
    정상적으로 사용자가 생성되고 나면 해당 사용자는 SignInAsync 메서드에 의해서 자동으로 로그인됩니다.
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Register(RegisterViewModel model)
    {
        if (ModelState.IsValid)
        {
            var user = new ApplicationUser() { UserName = model.UserName };
            var result = await UserManager.CreateAsync(user, model.Password);
            if (result.Succeeded)
            {
                await SignInAsync(user, isPersistent: false);
                return RedirectToAction("Index", "Home");
            }
            else
            {
                AddErrors(result);
            }
        }
    
        // If we got this far, something failed, redisplay form
        return View(model);
    }
    private async Task SignInAsync(ApplicationUser user, bool isPersistent)
    {
        AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
    
        var identity = await UserManager.CreateIdentityAsync(
            user, DefaultAuthenticationTypes.ApplicationCookie);
    
        AuthenticationManager.SignIn(
            new AuthenticationProperties() {
                IsPersistent = isPersistent 
            }, identity);
    }
    위의 SignInAsync 메서드에 강조되어 있는 코드는 ClaimsIdentity 클래스 개체를 생성해줍니다. ASP.NET Identity 및 OWIN 쿠키 인증은 클레임-기반 시스템이므로 응용 프로그램은 사용자에 대한 ClaimsIdentity 개체를 생성해서 프레임워크에 제공해줘야 합니다. ClaimsIdentity 개체는 사용자가 속해 있는 특정 역할 등, 사용자에 대한 모든 클레임들의 정보를 갖고 있습니다. 또한, 이 단계에서 사용자에 대한 더 많은 클레임들을 추가할 수도 있습니다.

    그리고, 다음 SignInAsync 메서드에 강조된 코드에서는 생성한 ClaimsIdentity 개체를 전달해서 OWIN의 AuthenticationManager 클래스의 SignIn 메서드를 호출함으로써 사용자를 로그인시킵니다.
    private async Task SignInAsync(ApplicationUser user, bool isPersistent)
    {
        AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
    
        var identity = await UserManager.CreateIdentityAsync(
            user, DefaultAuthenticationTypes.ApplicationCookie);
    
        AuthenticationManager.SignIn(
            new AuthenticationProperties() {
                IsPersistent = isPersistent
            }, identity);
    }
  5. 로그 오프
    로그 오프(Log off) 링크를 클릭하면 Account 컨트롤러의 LogOff 액션이 호출됩니다.
    // POST: /Account/LogOff
    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult LogOff()
    {
        AuthenticationManager.SignOut();
        return RedirectToAction("Index", "Home");
    }
    이 코드에서 강조된 부분은 OWIN의 AuthenticationManager.SignOut 메서드를 호출하는 구문입니다. 이 메서드는 Web Forms의 FormsAuthentication 클래스의 SignOut 메서드와 비슷한 작업을 수행해줍니다.

* 당연한 얘기겠지만 본문의 원문이 작성된 시점에 사용되던 패키지들의 버전과, 2014년 6월 현재 직접 테스트를 해보면서 검토한 패키지들의 버전에는 차이가 존재합니다. 가령, Update 2가 설치된 Visual Studio 2013으로 생성한 ASP.NET MVC 응용 프로그램에서는 세 가지 패키지 모두 2.0.0 버전이 사용되고 있으며, 이번 절에서 살펴보고 있는 예제 코드에도 제법 차이가 존재합니다. 게다가, NuGet 카탈로그에 등록되어 있는 이 패키지들의 최신 버전은 현재 2.0.1입니다. 참고로, 다음 절의 다이어그램에 나타나 있는 패키지들의 버전은 모두 1.0.0입니다.

본문에서도 설명하고 있는 것처럼 ASP.NET 팀이 지속적으로 ASP.NET Identity 패키지들을 개선하고 있는 것입니다.

** 이 화면의 항목들도 Update 2가 설치된 Visual Studio 2013으로 생성한 ASP.NET MVC 응용 프로그램에서는 '전자 메일'과 '암호'로 변경되었습니다.

ASP.NET Identity의 구성 요소들

다음 다이어그램은 ASP.NET Identity 시스템의 구성 요소들을 보여주고 있습니다 (자세하게 살펴보려면 여기나 다이어그램을 클릭하십시오). 이 다이어그램에서 녹색으로 표시된 패키지들이 바로 ASP.NET Identity 시스템을 구성하는 패키지들입니다. 그리고, 그 외의 다른 패키지들은 ASP.NET 응용 프로그램에서 ASP.NET Identity 시스템을 사용하기 위해서 필요한 의존적 구성 요소들입니다.

다음은 본문에서 언급하지 않은 NuGet 패키지들에 대한 간단한 설명입니다:

  • Microsoft.Owin.Security.Cookies
    응용 프로그램에서 ASP.NET의 폼 인증과 비슷한 쿠키 기반 인증을 사용할 수 있게 해주는 미들웨어입니다.
  • EntityFramework
    Entity Framework는 관계형 데이터베이스에 대한 Microsoft의 권장 데이터 접근 기술입니다.

멤버십에서 ASP.NET Identity로 마이그레이션하기

머지않아 ASP.NET 멤버십이나 단순 멤버십을 사용하고 있는 기존 응용 프로그램을 새로운 ASP.NET Identity 시스템으로 마이그레이션하는 방법에 대한 지침을 제공할 수 있게 되기를 희망합니다.

후속 과정