Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.NET Core Identity, How to override IdentityRole Name unique index? I want to store duplicate name with respect to tenant

I am writing extension of IdentityRoleManager to allow Multi-tenant roles. Where Role could be of same name in different Tenants where they can assign their own Claims to Roles.

How to allow duplicate Role name in the table? Role names will be unique for each tenant which i am intent to implement through RoleManager.

Tried OnModelCreating FluentApi but it doesnt give object to pass as annotation like in EF6

builder.Entity().ToTable("PenRoles") .Property(p => p.Name).HasAnnotation("Index", new _____{ });

How to do it?

like image 313
Nabeel Avatar asked Oct 19 '25 14:10

Nabeel


1 Answers

change role fluent api config:

public class RoleConfiguration : IEntityTypeConfiguration<Role>
{
    public void Configure(EntityTypeBuilder<Role> builder)
    {
        builder.Metadata.RemoveIndex(new[] { builder.Property(r => r.NormalizedName).Metadata });

        builder.HasIndex(r => new { r.NormalizedName, r.ApplicationId }).HasName("RoleNameIndex").IsUnique();
    }
}

then override RoleValidator:

public class MyRoleValidator : RoleValidator<Role>
{
    public override async Task<IdentityResult> ValidateAsync(RoleManager<Role> manager, Role role)
    {
        var roleName = await manager.GetRoleNameAsync(role);
        if (string.IsNullOrWhiteSpace(roleName))
        {
            return IdentityResult.Failed(new IdentityError
            {
                Code = "RoleNameIsNotValid",
                Description = "Role Name is not valid!"
            });
        }
        else
        {
            var owner = await manager.Roles.FirstOrDefaultAsync(x => x.ApplicationId == role.ApplicationId && x.NormalizedName == roleName);

            if (owner != null && !string.Equals(manager.GetRoleIdAsync(owner), manager.GetRoleIdAsync(role)))
            {
                return IdentityResult.Failed(new IdentityError
                {
                    Code = "DuplicateRoleName",
                    Description = "this role already exist in this App!"
                });
            }
        }
        return IdentityResult.Success;
    }
}

then register to DI container and change asp net identity config in Startup file to use this class :

    public static IServiceCollection ConfigureIdentity(this IServiceCollection services, IConfiguration configuration)
    {
        services.AddScoped<IRoleValidator<Role>, MyRoleValidator>(); //this line...
        services.AddIdentity<ApplicationUser, Role>(options =>
        {
            options.Password.RequiredLength = configuration.GetSection(nameof(IdentitySettings)).Get<IdentitySettings>().PasswordRequiredLength;
            options.Password.RequireLowercase = configuration.GetSection(nameof(IdentitySettings)).Get<IdentitySettings>().PasswordRequireLowercase;
            options.Password.RequireUppercase = configuration.GetSection(nameof(IdentitySettings)).Get<IdentitySettings>().PasswordRequireUppercase;
            options.Password.RequireNonAlphanumeric = configuration.GetSection(nameof(IdentitySettings)).Get<IdentitySettings>().PasswordRequireNonAlphanumeric;
            options.Password.RequireDigit = configuration.GetSection(nameof(IdentitySettings)).Get<IdentitySettings>().PasswordRequireDigit;
        })
            .AddRoleValidator<MyRoleValidator>() //this line ...
            .AddEntityFrameworkStores<SepidIdentityContext>()
            .AddDefaultTokenProviders();

        return services;
    }
like image 60
Heidar Ahmadi Avatar answered Oct 21 '25 03:10

Heidar Ahmadi



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!