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 の例では、Startup.cs
で Identity を使用して Facebook 認証を構成しています。
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 の例では、Startup.cs
で Identity を使用して Facebook 認証を構成しています。
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
メソッドでは、1 つの認証ミドルウェア コンポーネントが追加され、これが、自動認証とリモート認証要求の処理を担当します。 これにより、個々のミドルウェアはすべて、単一の共通ミドルウェア コンポーネントに置き換えられます。
以下では、2.0 への移行手順を主要な認証スキーム別に説明します。
Cookie ベースの認証
次の 2 つのオプションのいずれかを選択し、Startup.cs
で必要な変更を行います。
Identity 付きでCookie を使用する
Configure
メソッドで、UseIdentity
を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 なしで Cookie を使用する
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
メソッドに渡して既定のスキームを設定する必要があります。
OpenID Connect (OIDC) 認証
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 では、AuthenticationOptions 基底クラスの AutomaticAuthenticate
および AutomaticChallenge
プロパティは、単一の認証スキームについて設定するためのものでした。 これを適用する適切な方法がありませんでした。
2.0 では、個々の AuthenticationOptions
インスタンスのプロパティとして使用されていたこれら 2 つのプロパティは削除されました。 これらは、Startup.cs
の ConfigureServices
メソッド内の AddAuthentication
メソッド呼び出しで構成できます。
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);
前述のコード スニペットでは、既定のスキームを CookieAuthenticationDefaults.AuthenticationScheme
("Cookies") に設定しています。
または、AddAuthentication
メソッドのオーバーロードされたバージョンを使用して、複数のプロパティを設定します。 次のオーバーロードされたメソッドの例では、既定のスキームを CookieAuthenticationDefaults.AuthenticationScheme
に設定しています。 または、個々の [Authorize]
属性または承認ポリシー内で認証スキームを指定することもできます。
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
});
次のいずれかの条件に該当する場合、2.0 の既定のスキームを定義します。
- ユーザーを自動的にサインインさせる
- スキームを指定せずに
[Authorize]
属性または承認ポリシーを使用する
この規則の例外は、AddIdentity
メソッドです。 このメソッドでは、Cookie を追加し、既定の認証およびチャレンジ スキームをアプリケーション cookieIdentityConstants.ApplicationScheme
に設定します。 または、既定のサインイン スキームが外部 cookie の IdentityConstants.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 つのバリエーションがあります。
ホストでは、認証されたユーザーのみが許可されます。 このバリエーションは、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 (単純な従来の CLR オブジェクト) の Entity Framework (EF) 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
では、foreach
ループでアクセスされる AuthenticationScheme
プロパティが 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 イシュー「Auth 2.0 の説明」を参照してください。
ASP.NET Core