wake-up-neo.com

Mehrere Identitäten in ASP.NET Core 2.0

Ich migriere eine ASP.NET Core 1.0-Anwendung zu ASP.NET Core 2.0.

In meinem Start konfiguriere ich zwei Identitäten:

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>>();

Dies funktionierte gut in ASP.NET Core 1.0, schlägt jedoch mit dem Fehler fehl: System.InvalidOperationException: 'Schema ist bereits vorhanden: Identity.Application' in ASP.NET Core 2.0.

Wenn ich in ASP.NET Core 2.0 einen der Aufrufe von AddIdentity entferne, verschwindet der Fehler. Wie kann ich meinen Code migrieren, damit ich zwei verschiedene Arten von Identitätsbenutzern und Rollen in meiner Anwendung verwenden kann? Oder habe ich einfach einen fundamentalen Fehler gemacht, als ich das in ASP.NET Core 1.0 schrieb, als ich das geschrieben habe?

6
keith

Nachdem Sie den ASP.NET Core-Quellcode auf Github durchgesehen haben, kann mit dieser Erweiterungsmethode eine zweite Identität hinzugefügt werden:

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);
        }
    }
}
12
keith

Asp.net Core 2.2 bietet zu diesem Zweck eine integrierte Methode.

AddIdentityCore<TUser>

Wie man es benutzt:

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>>();

Lesen Sie in der Tat die Implementierung dieser Methode von 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);
    }
1
cyberdantes

Vielen Dank für Ihre Antwort, Keith. Das hat mir viel Zeit gespart! Eine kleine Verbesserung: Ich musste einige Optionen (IdentityOptions) in meinem Fall konfigurieren. Wie zum Beispiel: Regeln zur Kennwortkomplexität.

Ich habe daher die Registrierung der Action setupAction mit einbezogen. (Dies ist die gleiche Art und Weise, wie Microsoft dies innerhalb der AddIdentity in IdentityServiceCollectionExtension durchführt.)

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);
    }
}
0
Riscie