【问题标题】:Multiple Identities in ASP.NET Core 2.0ASP.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 中编写此代码时,我只是在理解事情如何恢复时犯了一个根本性错误?

【问题讨论】:

    标签: c# asp.net-core asp.net-core-identity


    【解决方案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&lt;..&gt; 作为我的第一个身份,然后使用services.AddSecondIdentity&lt;..&gt; 作为我的第二个身份。为什么我们需要这种扩展方法?
    • @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.AddRoles{TRole}"/>.
        /// </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() .AddEntityFrameworkStores(); services.AddSecondIdentity() .AddEntityFrameworkStores();但不知道如何初始化那些 2 来使用
      猜你喜欢
      • 1970-01-01
      • 2018-01-30
      • 2018-01-24
      • 2018-06-23
      • 1970-01-01
      • 2018-01-23
      • 2018-04-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多