ASP.NET Core 2.0으로 인증 및 Identity 마이그레이션
작성자: Scott Addie 및 Hao Kung
ASP.NET Core 2.0에는 인증 및 Identity를 위한 새 모델이 있으며 서비스를 사용하여 구성을 간소화합니다. 인증 또는 Identity를 사용하는 ASP.NET Core 1.x 애플리케이션은 다음에 설명된 대로 새 모델을 사용하도록 업데이트될 수 있습니다.
네임스페이스 업데이트
1.x에서 IdentityRole
및 IdentityUser
와 같은 클래스는 Microsoft.AspNetCore.Identity.EntityFrameworkCore
네임스페이스에 있습니다.
2.0 Microsoft.AspNetCore.Identity 에서 네임스페이스는 이러한 여러 클래스의 새로운 home 클래스가 되었습니다. 기본 Identity 코드를 사용하는 경우 영향을 받는 클래스에는 ApplicationUser
및 Startup
이 포함됩니다. 영향을 받는 참조를 확인하도록 using
문을 조정합니다.
인증 미들웨어 및 서비스
1.x 프로젝트에서 인증은 미들웨어를 통해 구성됩니다. 지원하려는 각 인증 체계에 대해 미들웨어 메서드가 호출됩니다.
다음 1.x 예제에서는 다음에서 Facebook 인증을 Identity 구성합니다.Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory)
{
app.UseIdentity();
app.UseFacebookAuthentication(new FacebookOptions {
AppId = Configuration["auth:facebook:appid"],
AppSecret = Configuration["auth:facebook:appsecret"]
});
}
2.0 프로젝트에서 인증은 서비스를 통해 구성됩니다. 각 인증 체계는 .의 Startup.cs
메서드에 ConfigureServices
등록됩니다. UseIdentity
메서드는 UseAuthentication
으로 대체됩니다.
다음 2.0 예제에서는 다음에서 Facebook 인증을 Identity 구성합니다.Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
// If you want to tweak Identity cookies, they're no longer part of IdentityOptions.
services.ConfigureApplicationCookie(options => options.LoginPath = "/Account/LogIn");
services.AddAuthentication()
.AddFacebook(options =>
{
options.AppId = Configuration["auth:facebook:appid"];
options.AppSecret = Configuration["auth:facebook:appsecret"];
});
}
public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory) {
app.UseAuthentication();
}
UseAuthentication
메서드는 자동 인증 및 원격 인증 요청 처리를 담당하는 단일 인증 미들웨어 구성 요소를 추가합니다. 모든 개별 미들웨어 구성 요소를 하나의 공통 미들웨어 구성 요소로 바꿉니다.
각 주요 인증 체계에 대한 2.0 마이그레이션 지침은 다음과 같습니다.
Cookie 기반 인증
아래의 두 옵션 중 하나를 선택하고 다음에서 필요한 내용을 변경합니다.Startup.cs
과 함께 쿠키 사용 Identity
UseIdentity
를Configure
메서드의UseAuthentication
으로 대체합니다.app.UseAuthentication();
ConfigureServices
메서드에서AddIdentity
메서드를 호출하여 cookie 인증 서비스를 추가합니다.필요에 따라
ConfigureServices
메서드에서ConfigureApplicationCookie
또는ConfigureExternalCookie
메서드를 호출하여 Identitycookie 설정을 조정합니다.services.AddIdentity<ApplicationUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders(); services.ConfigureApplicationCookie(options => options.LoginPath = "/Account/LogIn");
쿠키 없이 쿠키 사용 Identity
Configure
메서드의UseCookieAuthentication
메서드 호출을UseAuthentication
으로 바꿉니다.app.UseAuthentication();
ConfigureServices
메서드에서AddAuthentication
및AddCookie
메서드를 호출합니다.// If you don't want the cookie to be automatically authenticated and assigned to HttpContext.User, // remove the CookieAuthenticationDefaults.AuthenticationScheme parameter passed to AddAuthentication. services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme) .AddCookie(options => { options.LoginPath = "/Account/LogIn"; options.LogoutPath = "/Account/LogOff"; });
JWT 전달자 인증
Startup.cs
에서 다음과 같이 변경합니다.
Configure
메서드의UseJwtBearerAuthentication
메서드 호출을UseAuthentication
으로 바꿉니다.app.UseAuthentication();
ConfigureServices
메서드에서AddJwtBearer
메서드를 호출합니다.services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options => { options.Audience = "http://localhost:5001/"; options.Authority = "http://localhost:5000/"; });
이 코드 조각에서는 Identity를 사용하지 않으므로
JwtBearerDefaults.AuthenticationScheme
을AddAuthentication
메서드에 전달하여 기본 체계를 설정해야 합니다.
OIDC(OpenID Connect) 인증
Startup.cs
에서 다음과 같이 변경합니다.
Configure
메서드의UseOpenIdConnectAuthentication
메서드 호출을UseAuthentication
으로 바꿉니다.app.UseAuthentication();
ConfigureServices
메서드에서AddOpenIdConnect
메서드를 호출합니다.services.AddAuthentication(options => { options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme; options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme; }) .AddCookie() .AddOpenIdConnect(options => { options.Authority = Configuration["auth:oidc:authority"]; options.ClientId = Configuration["auth:oidc:clientid"]; });
OpenIdConnectOptions
작업의PostLogoutRedirectUri
속성을SignedOutRedirectUri
로 바꿉니다..AddOpenIdConnect(options => { options.SignedOutRedirectUri = "https://contoso.com"; });
Facebook 인증
Startup.cs
에서 다음과 같이 변경합니다.
Configure
메서드의UseFacebookAuthentication
메서드 호출을UseAuthentication
으로 바꿉니다.app.UseAuthentication();
ConfigureServices
메서드에서AddFacebook
메서드를 호출합니다.services.AddAuthentication() .AddFacebook(options => { options.AppId = Configuration["auth:facebook:appid"]; options.AppSecret = Configuration["auth:facebook:appsecret"]; });
Google 인증
Startup.cs
에서 다음과 같이 변경합니다.
Configure
메서드의UseGoogleAuthentication
메서드 호출을UseAuthentication
으로 바꿉니다.app.UseAuthentication();
ConfigureServices
메서드에서AddGoogle
메서드를 호출합니다.services.AddAuthentication() .AddGoogle(options => { options.ClientId = Configuration["auth:google:clientid"]; options.ClientSecret = Configuration["auth:google:clientsecret"]; });
Microsoft 계정 인증
Microsoft 계정 인증에 대한 자세한 내용은 이 GitHub 문제를 참조하세요.
Startup.cs
에서 다음과 같이 변경합니다.
Configure
메서드의UseMicrosoftAccountAuthentication
메서드 호출을UseAuthentication
으로 바꿉니다.app.UseAuthentication();
ConfigureServices
메서드에서AddMicrosoftAccount
메서드를 호출합니다.services.AddAuthentication() .AddMicrosoftAccount(options => { options.ClientId = Configuration["auth:microsoft:clientid"]; options.ClientSecret = Configuration["auth:microsoft:clientsecret"]; });
Twitter 인증
Startup.cs
에서 다음과 같이 변경합니다.
Configure
메서드의UseTwitterAuthentication
메서드 호출을UseAuthentication
으로 바꿉니다.app.UseAuthentication();
ConfigureServices
메서드에서AddTwitter
메서드를 호출합니다.services.AddAuthentication() .AddTwitter(options => { options.ConsumerKey = Configuration["auth:twitter:consumerkey"]; options.ConsumerSecret = Configuration["auth:twitter:consumersecret"]; });
기본 인증 체계 설정
1.x AutomaticAuthenticate
에서는 기본 클래스의 AuthenticationOptions 속성과 AutomaticChallenge
속성을 단일 인증 체계로 설정해야 했습니다. 이를 적용하는 좋은 방법은 없습니다.
2.0에서는 이러한 두 속성이 개별 AuthenticationOptions
인스턴스에서 속성으로 제거되었습니다. 다음 메서드 Startup.cs
내의 AddAuthentication
메서드 호출 ConfigureServices
에서 구성할 수 있습니다.
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);
앞의 코드 조각에서 기본 구성표는 ("Cookies")로 CookieAuthenticationDefaults.AuthenticationScheme
설정됩니다.
또는 오버로드된 버전의 AddAuthentication
메서드를 사용하여 둘 이상의 속성을 설정합니다. 다음 오버로드된 메서드 예제에서 기본 체계는 CookieAuthenticationDefaults.AuthenticationScheme
으로 설정됩니다. 개별 [Authorize]
특성 또는 권한 부여 정책 내에서 인증 체계를 지정할 수 있습니다.
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
});
다음 조건 중 하나에 해당하는 경우 2.0에서 기본 스키마를 정의합니다.
- 사용자에게 자동으로 로그인하려고 합니다.
- 스키마를 지정하지 않고
[Authorize]
특성 또는 권한 부여 정책을 사용합니다.
이 규칙의 예외는 AddIdentity
메서드입니다. 이 메서드는 사용자를 위해 쿠키를 추가하고 기본 인증 및 챌린지 체계를 애플리케이션 cookieIdentityConstants.ApplicationScheme
에 설정합니다. 또한 기본 로그인 체계를 외부 cookieIdentityConstants.ExternalScheme
으로 설정합니다.
HttpContext 인증 확장 프로그램 사용
IAuthenticationManager
인터페이스는 1.x 인증 시스템의 기본 진입점입니다. Microsoft.AspNetCore.Authentication
네임스페이스의 새로운 HttpContext
확장 메서드 집합으로 대체되었습니다.
예를 들어 1.x 프로젝트는 Authentication
속성을 참조합니다.
// Clear the existing external cookie to ensure a clean login process
await HttpContext.Authentication.SignOutAsync(_externalCookieScheme);
2.0 프로젝트에서 Microsoft.AspNetCore.Authentication
네임스페이스를 가져오고 Authentication
속성 참조를 삭제합니다.
// Clear the existing external cookie to ensure a clean login process
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
Windows 인증(HTTP.sys/IISIntegration)
Windows 인증에는 두 가지 변형이 있습니다.
호스트는 인증된 사용자만 허용합니다. 이러한 변형은 2.0 변경의 영향을 받지 않습니다.
호스트는 익명 및 인증된 사용자를 모두 허용합니다. 이러한 변형은 2.0 변경의 영향을 받습니다. 예를 들어 앱은 IIS 또는 HTTP.sys 계층에서 익명 사용자를 허용하지만 컨트롤러 수준에서 사용자에게 권한을 부여해야 합니다. 이 시나리오에서는
Startup.ConfigureServices
메서드의 기본 스키마를 설정합니다.Microsoft.AspNetCore.Server.IISIntegration의 경우 기본 체계를
IISDefaults.AuthenticationScheme
으로 설정합니다.using Microsoft.AspNetCore.Server.IISIntegration; services.AddAuthentication(IISDefaults.AuthenticationScheme);
Microsoft.AspNetCore.Server.HttpSys의 경우 기본 체계를
HttpSysDefaults.AuthenticationScheme
으로 설정합니다.using Microsoft.AspNetCore.Server.HttpSys; services.AddAuthentication(HttpSysDefaults.AuthenticationScheme);
기본 체계를 설정하지 않으면 권한 부여(챌린지) 요청이 다음 예외와 함께 작동하지 않습니다.
System.InvalidOperationException
: authenticationScheme이 지정되지 않았으며 DefaultChallengeScheme을 찾을 수 없습니다.
자세한 내용은 ASP.NET Core에서 Windows 인증 구성을 참조하세요.
IdentityCookieOptions 인스턴스
2.0 변경의 부작용은 cookie 옵션 인스턴스 대신 명명된 옵션을 사용하는 것으로 전환되는 것입니다. Identitycookie 스키마 이름을 사용자 지정하는 기능이 제거됩니다.
예를 들어 1.x 프로젝트는 생성자 주입을 사용하여 매개 변수를 전달 IdentityCookieOptions
AccountController.cs
합니다.ManageController.cs
외부 cookie 인증 체계는 제공된 인스턴스에서 액세스할 수 있습니다.
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IOptions<IdentityCookieOptions> identityCookieOptions,
IEmailSender emailSender,
ISmsSender smsSender,
ILoggerFactory loggerFactory)
{
_userManager = userManager;
_signInManager = signInManager;
_externalCookieScheme = identityCookieOptions.Value.ExternalCookieAuthenticationScheme;
_emailSender = emailSender;
_smsSender = smsSender;
_logger = loggerFactory.CreateLogger<AccountController>();
}
앞에서 언급한 생성자 삽입은 2.0 프로젝트에서 필요하지 않으며 _externalCookieScheme
필드를 삭제할 수 있습니다.
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IEmailSender emailSender,
ISmsSender smsSender,
ILoggerFactory loggerFactory)
{
_userManager = userManager;
_signInManager = signInManager;
_emailSender = emailSender;
_smsSender = smsSender;
_logger = loggerFactory.CreateLogger<AccountController>();
}
1.x 프로젝트는 다음과 같이 _externalCookieScheme
필드를 사용했습니다.
// Clear the existing external cookie to ensure a clean login process
await HttpContext.Authentication.SignOutAsync(_externalCookieScheme);
2.0 프로젝트에서 위의 코드를 다음으로 바꿉니다. IdentityConstants.ExternalScheme
상수는 직접 사용할 수 있습니다.
// Clear the existing external cookie to ensure a clean login process
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
다음 네임스페이스를 가져와서 새로 추가된 SignOutAsync
호출을 해결합니다.
using Microsoft.AspNetCore.Authentication;
IdentityUser POCO 탐색 속성 추가
기본 IdentityUser
POCO(Plain Old CLR Object)의 EF(Entity Framework) Core 탐색 속성이 제거되었습니다. 1.x 프로젝트에서 이러한 속성을 사용한 경우 수동으로 2.0 프로젝트에 다시 추가합니다.
/// <summary>
/// Navigation property for the roles this user belongs to.
/// </summary>
public virtual ICollection<IdentityUserRole<int>> Roles { get; } = new List<IdentityUserRole<int>>();
/// <summary>
/// Navigation property for the claims this user possesses.
/// </summary>
public virtual ICollection<IdentityUserClaim<int>> Claims { get; } = new List<IdentityUserClaim<int>>();
/// <summary>
/// Navigation property for this users login accounts.
/// </summary>
public virtual ICollection<IdentityUserLogin<int>> Logins { get; } = new List<IdentityUserLogin<int>>();
EF Core 마이그레이션을 실행할 때 중복 외래 키를 방지하려면 IdentityDbContext
클래스의 OnModelCreating
메서드(base.OnModelCreating();
호출 후)에 다음을 추가합니다.
protected override void OnModelCreating(ModelBuilder builder)
{
base.OnModelCreating(builder);
// Customize the ASP.NET Core Identity model and override the defaults if needed.
// For example, you can rename the ASP.NET Core Identity table names and more.
// Add your customizations after calling base.OnModelCreating(builder);
builder.Entity<ApplicationUser>()
.HasMany(e => e.Claims)
.WithOne()
.HasForeignKey(e => e.UserId)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
builder.Entity<ApplicationUser>()
.HasMany(e => e.Logins)
.WithOne()
.HasForeignKey(e => e.UserId)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
builder.Entity<ApplicationUser>()
.HasMany(e => e.Roles)
.WithOne()
.HasForeignKey(e => e.UserId)
.IsRequired()
.OnDelete(DeleteBehavior.Cascade);
}
GetExternalAuthenticationSchemes 바꾸기
비동기 버전을 위해 동기 메서드 GetExternalAuthenticationSchemes
가 제거되었습니다. 1.x 프로젝트에는 다음 코드가 있습니다.Controllers/ManageController.cs
var otherLogins = _signInManager.GetExternalAuthenticationSchemes().Where(auth => userLogins.All(ul => auth.AuthenticationScheme != ul.LoginProvider)).ToList();
이 메서드도 다음과 같이 표시됩니다.Views/Account/Login.cshtml
@{
var loginProviders = SignInManager.GetExternalAuthenticationSchemes().ToList();
if (loginProviders.Count == 0)
{
<div>
<p>
There are no external authentication services configured. See <a href="https://go.microsoft.com/fwlink/?LinkID=532715">this article</a>
for details on setting up this ASP.NET application to support logging in via external services.
</p>
</div>
}
else
{
<form asp-controller="Account" asp-action="ExternalLogin" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal">
<div>
<p>
@foreach (var provider in loginProviders)
{
<button type="submit" class="btn btn-default" name="provider" value="@provider.AuthenticationScheme" title="Log in using your @provider.DisplayName account">@provider.AuthenticationScheme</button>
}
</p>
</div>
</form>
}
}
2.0 프로젝트에서는 GetExternalAuthenticationSchemesAsync 메서드를 사용합니다. 변경 ManageController.cs
내용은 다음 코드와 유사합니다.
var schemes = await _signInManager.GetExternalAuthenticationSchemesAsync();
var otherLogins = schemes.Where(auth => userLogins.All(ul => auth.Name != ul.LoginProvider)).ToList();
에서 Login.cshtml
루프에 AuthenticationScheme
액세스하는 속성은 foreach
다음과 같이 변경됩니다 Name
.
@{
var loginProviders = (await SignInManager.GetExternalAuthenticationSchemesAsync()).ToList();
if (loginProviders.Count == 0)
{
<div>
<p>
There are no external authentication services configured. See <a href="https://go.microsoft.com/fwlink/?LinkID=532715">this article</a>
for details on setting up this ASP.NET application to support logging in via external services.
</p>
</div>
}
else
{
<form asp-controller="Account" asp-action="ExternalLogin" asp-route-returnurl="@ViewData["ReturnUrl"]" method="post" class="form-horizontal">
<div>
<p>
@foreach (var provider in loginProviders)
{
<button type="submit" class="btn btn-default" name="provider" value="@provider.Name" title="Log in using your @provider.DisplayName account">@provider.DisplayName</button>
}
</p>
</div>
</form>
}
}
ManageLoginsViewModel 속성 변경
ManageLoginsViewModel
개체는 .의 ManageController.cs
동작에 ManageLogins
사용됩니다. 1.x 프로젝트에서 개체의 OtherLogins
속성 반환 형식은 IList<AuthenticationDescription>
입니다. 이 반환 형식을 사용하려면 Microsoft.AspNetCore.Http.Authentication
을 가져와야 합니다.
using System.Collections.Generic;
using Microsoft.AspNetCore.Http.Authentication;
using Microsoft.AspNetCore.Identity;
namespace AspNetCoreDotNetCore1App.Models.ManageViewModels
{
public class ManageLoginsViewModel
{
public IList<UserLoginInfo> CurrentLogins { get; set; }
public IList<AuthenticationDescription> OtherLogins { get; set; }
}
}
2.0 프로젝트에서 반환 형식은 IList<AuthenticationScheme>
으로 변경합니다. 이 새 반환 형식을 사용하려면 Microsoft.AspNetCore.Http.Authentication
가져오기를 Microsoft.AspNetCore.Authentication
가져오기로 대체해야 합니다.
using System.Collections.Generic;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
namespace AspNetCoreDotNetCore2App.Models.ManageViewModels
{
public class ManageLoginsViewModel
{
public IList<UserLoginInfo> CurrentLogins { get; set; }
public IList<AuthenticationScheme> OtherLogins { get; set; }
}
}
추가 리소스
자세한 내용은 GitHub의 인증 2.0 토론 문제를 참조하세요.
ASP.NET Core