- 将身份验证和标识迁移到 ASP.NET Core 2.0Migrate authentication and Identity to ASP.NET Core 2.0
- 更新命名空间Update namespaces
- 身份验证中间件和服务Authentication Middleware and services
- 基于 Cookie 的身份验证Cookie-based authentication
- JWT 持有者身份验证JWT Bearer Authentication
- OpenID Connect (OIDC)身份验证OpenID Connect (OIDC) authentication
- Facebook 身份验证Facebook authentication
- Google 身份验证Google authentication
- Microsoft 帐户身份验证Microsoft Account authentication
- Twitter 身份验证Twitter authentication
- 设置默认身份验证方案Setting default authentication schemes
- 使用 HttpContext 身份验证扩展Use HttpContext authentication extensions
- Windows 身份验证(http.sys/IISIntegration)Windows Authentication (HTTP.sys / IISIntegration)
- IdentityCookieOptions 实例IdentityCookieOptions instances
- 添加 IdentityUser POCO 导航属性Add IdentityUser POCO navigation properties
- 替换 GetExternalAuthenticationSchemesReplace GetExternalAuthenticationSchemes
- ManageLoginsViewModel 属性更改ManageLoginsViewModel property change
- 其他资源Additional resources
将身份验证和标识迁移到 ASP.NET Core 2.0Migrate authentication and Identity to ASP.NET Core 2.0
本文内容
作者: Scott Addie和Hao Kung
ASP.NET Core 2.0 具有新的身份验证和标识模型,可通过使用服务简化配置。ASP.NET Core 1.x 应用程序使用身份验证或标识可以更新以使用新的模型,如下所述。
更新命名空间Update namespaces
在1.x 中,在 Microsoft.AspNetCore.Identity.EntityFrameworkCore
命名空间中找到了类 IdentityRole
和 IdentityUser
。
在2.0 中,Microsoft.AspNetCore.Identity 命名空间成为几个此类类的新宿主。对于默认标识代码,受影响的类包括 ApplicationUser
和 Startup
。调整 using
语句以解析受影响的引用。
身份验证中间件和服务Authentication Middleware and services
在1.x 项目中,通过中间件配置身份验证。为要支持的每个身份验证方案调用中间件方法。
下面的1.x 示例在Startup.cs中配置具有标识的 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中配置具有标识的 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
方法添加单个身份验证中间件组件,该组件负责自动身份验证和远程身份验证请求的处理。它将所有单个中间件组件替换为一个公共中间件组件。
下面是每个主要身份验证方案的2.0 迁移说明。
基于 Cookie 的身份验证Cookie-based authentication
选择以下两个选项之一,并在Startup.cs中进行必要的更改:
使用带有标识的 cookie
- 将
UseIdentity
替换为Configure
方法中的UseAuthentication
:
- 将
app.UseAuthentication();
在
ConfigureServices
方法中调用AddIdentity
方法,以添加 cookie 身份验证服务。(可选)调用
ConfigureServices
方法中的ConfigureApplicationCookie
或ConfigureExternalCookie
方法以调整标识 cookie 设置。
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.ConfigureApplicationCookie(options => options.LoginPath = "/Account/LogIn");
使用没有标识的 cookie
- 用
UseAuthentication
替换Configure
方法中的UseCookieAuthentication
方法调用:
- 用
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 持有者身份验证JWT Bearer Authentication
在Startup.cs中进行以下更改:
- 用
UseAuthentication
替换Configure
方法中的UseJwtBearerAuthentication
方法调用:
app.UseAuthentication();
- 在
ConfigureServices
方法中调用AddJwtBearer
方法:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.Audience = "http://localhost:5001/";
options.Authority = "http://localhost:5000/";
});
此代码片段不使用标识,因此应通过将 JwtBearerDefaults.AuthenticationScheme
传递到 AddAuthentication
方法来设置默认方案。
OpenID Connect (OIDC)身份验证OpenID Connect (OIDC) authentication
在Startup.cs中进行以下更改:
- 用
UseAuthentication
替换Configure
方法中的UseOpenIdConnectAuthentication
方法调用:
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 身份验证Facebook authentication
在Startup.cs中进行以下更改:
- 用
UseAuthentication
替换Configure
方法中的UseFacebookAuthentication
方法调用:
app.UseAuthentication();
- 在
ConfigureServices
方法中调用AddFacebook
方法:
services.AddAuthentication()
.AddFacebook(options =>
{
options.AppId = Configuration["auth:facebook:appid"];
options.AppSecret = Configuration["auth:facebook:appsecret"];
});
Google 身份验证Google authentication
在Startup.cs中进行以下更改:
- 用
UseAuthentication
替换Configure
方法中的UseGoogleAuthentication
方法调用:
app.UseAuthentication();
- 在
ConfigureServices
方法中调用AddGoogle
方法:
services.AddAuthentication()
.AddGoogle(options =>
{
options.ClientId = Configuration["auth:google:clientid"];
options.ClientSecret = Configuration["auth:google:clientsecret"];
});
Microsoft 帐户身份验证Microsoft Account authentication
有关 Microsoft 帐户身份验证的详细信息,请参阅此 GitHub 问题。
在Startup.cs中进行以下更改:
- 用
UseAuthentication
替换Configure
方法中的UseMicrosoftAccountAuthentication
方法调用:
app.UseAuthentication();
- 在
ConfigureServices
方法中调用AddMicrosoftAccount
方法:
services.AddAuthentication()
.AddMicrosoftAccount(options =>
{
options.ClientId = Configuration["auth:microsoft:clientid"];
options.ClientSecret = Configuration["auth:microsoft:clientsecret"];
});
Twitter 身份验证Twitter authentication
在Startup.cs中进行以下更改:
- 用
UseAuthentication
替换Configure
方法中的UseTwitterAuthentication
方法调用:
app.UseAuthentication();
- 在
ConfigureServices
方法中调用AddTwitter
方法:
services.AddAuthentication()
.AddTwitter(options =>
{
options.ConsumerKey = Configuration["auth:twitter:consumerkey"];
options.ConsumerSecret = Configuration["auth:twitter:consumersecret"];
});
设置默认身份验证方案Setting default authentication schemes
在1.x 中, AuthenticationOptions基类的 AutomaticAuthenticate
和 AutomaticChallenge
属性应在单个身份验证方案上进行设置。没有正确的方法来强制执行此操作。
在2.0 中,已将这两个属性作为单独 AuthenticationOptions
实例的属性删除。可以在Startup.cs的 ConfigureServices
方法中的 AddAuthentication
方法调用中配置它们:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);
在上面的代码段中,默认方案设置为 CookieAuthenticationDefaults.AuthenticationScheme
("Cookie")。
或者,使用 AddAuthentication
方法的重载版本设置多个属性。在下面的重载方法示例中,将默认方案设置为 CookieAuthenticationDefaults.AuthenticationScheme
。可以在单独的 [Authorize]
属性或授权策略中指定身份验证方案。
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
});
如果满足以下条件之一,则定义2.0 中的默认方案:
- 希望用户自动登录
- 在不指定方案的情况下使用
[Authorize]
属性或授权策略
此规则的例外情况是 AddIdentity
方法。此方法为你添加 cookie,并将默认身份验证和质询方案设置为应用程序 cookie IdentityConstants.ApplicationScheme
。此外,它还会将默认登录方案设置为外部 cookie IdentityConstants.ExternalScheme
。
使用 HttpContext 身份验证扩展Use HttpContext authentication extensions
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 Authentication (HTTP.sys / IISIntegration)
Windows 身份验证有两种变体:
该主机仅允许经过身份验证的用户。此变体不受2.0 更改的影响。
宿主允许匿名用户和经过身份验证的用户。此变体受2.0 更改的影响。例如,应用程序应允许IIS或http.sys层上的匿名用户,但在控制器级别对用户进行授权。在此方案中,在
Startup.ConfigureServices
方法中设置默认方案。
对于AspNetCore,请将默认方案设置为 IISDefaults.AuthenticationScheme
:
using Microsoft.AspNetCore.Server.IISIntegration;
services.AddAuthentication(IISDefaults.AuthenticationScheme);
对于AspNetCore,请将默认方案设置为 HttpSysDefaults.AuthenticationScheme
:
using Microsoft.AspNetCore.Server.HttpSys;
services.AddAuthentication(HttpSysDefaults.AuthenticationScheme);
未能设置默认方案会阻止授权(质询)请求使用以下例外:
System.InvalidOperationException
:未指定任何 authenticationScheme,并且找不到 DefaultChallengeScheme。
有关详细信息,请参阅 在 ASP.NET Core 中配置 Windows 身份验证。
IdentityCookieOptions 实例IdentityCookieOptions instances
2.0 更改的副作用是切换到使用命名选项而不是 cookie 选项实例。将删除自定义标识 cookie 方案名称的功能。
例如,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 导航属性Add IdentityUser POCO navigation properties
已删除基 IdentityUser
POCO (普通旧 CLR 对象)的实体框架(EF)核心导航属性。如果你的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);
}
替换 GetExternalAuthenticationSchemesReplace GetExternalAuthenticationSchemes
已删除同步方法 GetExternalAuthenticationSchemes
以支持异步版本。1.x 项目的控制器/ManageController中包含以下代码:
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中,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 property change
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.Authentication
导入替换 Microsoft.AspNetCore.Http.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; }
}
}
其他资源Additional resources
有关详细信息,请参阅 GitHub 上的有关 Auth 2.0问题的讨论。