ASP.NET Core 2.0 中的多个身份
Posted
技术标签:
【中文标题】ASP.NET Core 2.0 中的多个身份【英文标题】:Multiple Identities in ASP.NET Core 2.0 【发布时间】:2018-05-06 02:34:40 【问题描述】:我正在将 ASP.NET Core 1.0 应用程序迁移到 ASP.NET Core 2.0。
在我的启动中,我正在配置两个身份:
services.AddIdentity<IdentityUser, IdentityRole>(configureIdentity)
.AddDefaultTokenProviders()
.AddUserStore<IdentityUserStore<IdentityUser>>()
.AddRoleStore<IdentityRoleStore<IdentityRole>>();
services.AddIdentity<Customer, CustomerRole>(configureIdentity)
.AddDefaultTokenProviders()
.AddErrorDescriber<CustomerIdentityErrorDescriber>()
.AddUserStore<CustomerStore<Customer>>()
.AddRoleStore<CustomerRoleStore<CustomerRole>>();
这在 ASP.NET Core 1.0 中运行良好,但因错误而失败:System.InvalidOperationException: 'Scheme already exists: Identity.Application' in ASP.NET Core 2.0。
在 ASP.NET Core 2.0 中,如果我删除对 AddIdentity
的调用之一,错误就会消失。如何迁移我的代码,以便我可以在我的应用程序中使用两种不同类型的身份用户和角色?还是当我在 ASP.NET Core 1.0 中编写此代码时,我只是在理解事情如何恢复时犯了一个根本性错误?
【问题讨论】:
【参考方案1】:查看 github 上的 ASP.NET Core 源代码后,可以使用此扩展方法添加第二个身份:
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using System;
using System.Collections.Generic;
using System.Text;
namespace Whatever
public static class IdentityExtensions
public static IdentityBuilder AddSecondIdentity<TUser, TRole>(
this IServiceCollection services)
where TUser : class
where TRole : class
services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>();
services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>();
services.TryAddScoped<IRoleValidator<TRole>, RoleValidator<TRole>>();
services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<TUser>>();
services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser, TRole>>();
services.TryAddScoped<UserManager<TUser>, AspNetUserManager<TUser>>();
services.TryAddScoped<SignInManager<TUser>, SignInManager<TUser>>();
services.TryAddScoped<RoleManager<TRole>, AspNetRoleManager<TRole>>();
return new IdentityBuilder(typeof(TUser), typeof(TRole), services);
【讨论】:
这真的很有帮助。但是为什么我们必须添加 Create a builder 方法;AddSecondIdentity
?
@ShiroiTora,我不确定我是否完全理解这个问题:您的意思是 是否有必要使用扩展方法? 还是您的意思是 为什么微软这样改设计?
我会回答第一个问题。在启动时,我使用services.AddIdentity<..>
作为我的第一个身份,然后使用services.AddSecondIdentity<..>
作为我的第二个身份。为什么我们需要这种扩展方法?
@ShiroiTora,它不需要是扩展方法,但微软在 .NET Core 2.0 中改变了身份提供者的设计,使AddIdentity
不能用于添加更多身份。我认为他们的设计选择意味着应该使用单个身份,并且您应该在单个提供者中处理多个身份来源。我编写的扩展方法只是复制了 .NET Core 1.0 的行为方式,即它是从 .NET Core 的源代码中提取的。
我现在完全明白了。谢谢。【参考方案2】:
Asp.net Core 2.2 为此提供了一个内置方法。
AddIdentityCore<TUser>
使用方法:
services.AddIdentity<IdentityUser, IdentityRole>(configureIdentity)
.AddDefaultTokenProviders()
.AddUserStore<IdentityUserStore<IdentityUser>>()
.AddRoleStore<IdentityRoleStore<IdentityRole>>();
services.AddIdentityCore<Customer>(configureIdentity)
.AddDefaultTokenProviders()
.AddErrorDescriber<CustomerIdentityErrorDescriber>()
.AddUserStore<CustomerStore<Customer>>()
.AddRoleStore<CustomerRoleStore<CustomerRole>>();
services.AddScoped<RoleManager<Customer>>();
其实这个方法的实现从asp.net core 2.2 github repo看
/// <summary>
/// Adds and configures the identity system for the specified User type. Role services are not added by default
/// but can be added with <see cref="IdentityBuilder.AddRolesTRole"/>.
/// </summary>
/// <typeparam name="TUser">The type representing a User in the system.</typeparam>
/// <param name="services">The services available in the application.</param>
/// <param name="setupAction">An action to configure the <see cref="IdentityOptions"/>.</param>
/// <returns>An <see cref="IdentityBuilder"/> for creating and configuring the identity system.</returns>
public static IdentityBuilder AddIdentityCore<TUser>(this IServiceCollection services, Action<IdentityOptions> setupAction)
where TUser : class
// Services identity depends on
services.AddOptions().AddLogging();
// Services used by identity
services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>();
services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>();
services.TryAddScoped<ILookupNormalizer, UpperInvariantLookupNormalizer>();
services.TryAddScoped<IUserConfirmation<TUser>, DefaultUserConfirmation<TUser>>();
// No interface for the error describer so we can add errors without rev'ing the interface
services.TryAddScoped<IdentityErrorDescriber>();
services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser>>();
services.TryAddScoped<UserManager<TUser>>();
if (setupAction != null)
services.Configure(setupAction);
return new IdentityBuilder(typeof(TUser), services);
【讨论】:
【参考方案3】:非常感谢基思的回答。这为我节省了很多时间! 一个小的改进:在我的情况下,我必须配置一些选项(IdentityOptions)。例如:密码复杂性规则。
因此,我将操作 setupAction 的注册包括在内。 (这与 Microsoft 在 IdentityServiceCollectionExtension 中的 AddIdentity 中执行此操作的方式相同)
public static class IdentityExtensions
public static IdentityBuilder AddSecondIdentity<TUser, TRole>(
this IServiceCollection services, Action<IdentityOptions> setupAction)
where TUser : class
where TRole : class
services.TryAddScoped<IUserValidator<TUser>, UserValidator<TUser>>();
services.TryAddScoped<IPasswordValidator<TUser>, PasswordValidator<TUser>>();
services.TryAddScoped<IPasswordHasher<TUser>, PasswordHasher<TUser>>();
services.TryAddScoped<IRoleValidator<TRole>, RoleValidator<TRole>>();
services.TryAddScoped<ISecurityStampValidator, SecurityStampValidator<TUser>>();
services.TryAddScoped<IUserClaimsPrincipalFactory<TUser>, UserClaimsPrincipalFactory<TUser, TRole>>();
services.TryAddScoped<UserManager<TUser>, AspNetUserManager<TUser>>();
services.TryAddScoped<SignInManager<TUser>, SignInManager<TUser>>();
services.TryAddScoped<RoleManager<TRole>, AspNetRoleManager<TRole>>();
if (setupAction != null)
services.Configure(setupAction);
return new IdentityBuilder(typeof(TUser), typeof(TRole), services);
【讨论】:
我很困惑你们是如何使用它的?目前我有这个 services.AddDefaultIdentity以上是关于ASP.NET Core 2.0 中的多个身份的主要内容,如果未能解决你的问题,请参考以下文章
如何从 ASP.NET Core 2.0 中的自定义中间件请求身份验证
同一站点中的 asp net core 2.0 JWT 和 Openid Connect 身份验证