Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ASP.net Core 3 IdentityErrorDescriber Error Messages

I have an ASP.net Core 3.1 web application. I'm trying to customize the error message for "Invalid User Name" when creating a new User. I've created a custom class "CustomIdentityErrorDescriber" that inherits Microsoft.AspNetCore.Identity.IdentityErrorDescriber

public class CustomIdentityErrorDescriber : IdentityErrorDescriber
  {
        public override IdentityError DefaultError() { return new IdentityError { Code = nameof(DefaultError), Description = $"An unknown failure has occurred." }; }
        public override IdentityError ConcurrencyFailure() { return new IdentityError { Code = nameof(ConcurrencyFailure), Description = "Optimistic concurrency failure, object has been modified." }; }
        public override IdentityError PasswordMismatch() { return new IdentityError { Code = nameof(PasswordMismatch), Description = "Incorrect password." }; }
        public override IdentityError InvalidToken() { return new IdentityError { Code = nameof(InvalidToken), Description = "Invalid token." }; }
        public override IdentityError LoginAlreadyAssociated() { return new IdentityError { Code = nameof(LoginAlreadyAssociated), Description = "A user with this login already exists." }; }
        public override IdentityError InvalidUserName(string userName) { return new IdentityError { Code = nameof(InvalidUserName), Description = $"User name '{userName}' is invalid, allowable characters 'a-z 'A-Z'." }; }
        public override IdentityError InvalidEmail(string email) { return new IdentityError { Code = nameof(InvalidEmail), Description = $"Email '{email}' is invalid." }; }
        public override IdentityError DuplicateUserName(string userName) { return new IdentityError { Code = nameof(DuplicateUserName), Description = $"User Name '{userName}' is already taken." }; }
        public override IdentityError DuplicateEmail(string email) { return new IdentityError { Code = nameof(DuplicateEmail), Description = $"Email '{email}' is already taken." }; }
        public override IdentityError InvalidRoleName(string role) { return new IdentityError { Code = nameof(InvalidRoleName), Description = $"Role name '{role}' is invalid." }; }
        public override IdentityError DuplicateRoleName(string role) { return new IdentityError { Code = nameof(DuplicateRoleName), Description = $"Role name '{role}' is already taken." }; }
        public override IdentityError UserAlreadyHasPassword() { return new IdentityError { Code = nameof(UserAlreadyHasPassword), Description = "User already has a password set." }; }
        public override IdentityError UserLockoutNotEnabled() { return new IdentityError { Code = nameof(UserLockoutNotEnabled), Description = "Lockout is not enabled for this user." }; }
        public override IdentityError UserAlreadyInRole(string role) { return new IdentityError { Code = nameof(UserAlreadyInRole), Description = $"User already in role '{role}'." }; }
        public override IdentityError PasswordTooShort(int length) { return new IdentityError { Code = nameof(PasswordTooShort), Description = $"Passwords must be at least {length} characters." }; }
        public override IdentityError PasswordRequiresNonAlphanumeric() { return new IdentityError { Code = nameof(PasswordRequiresNonAlphanumeric), Description = "Passwords must have at least one non alphanumeric character." }; }
        public override IdentityError PasswordRequiresDigit() { return new IdentityError { Code = nameof(PasswordRequiresDigit), Description = "Passwords must have at least one digit ('0'-'9')." }; }
        public override IdentityError PasswordRequiresLower() { return new IdentityError { Code = nameof(PasswordRequiresLower), Description = "Passwords must have at least one lowercase ('a'-'z')." }; }
        public override IdentityError PasswordRequiresUpper() { return new IdentityError { Code = nameof(PasswordRequiresUpper), Description = "Passwords must have at least one uppercase ('A'-'Z')." }; }
    }

I've implemented my custom class in the startup.cs file as follows

services.AddTransient<IdentityErrorDescriber, CustomIdentityErrorDescriber>();

            services.Configure<IdentityOptions>(opts =>
            {
                // opts.User.RequireUniqueEmail = true;
                opts.User.AllowedUserNameCharacters =
                        "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._";
                 opts.Password.RequiredLength = 8;
                opts.Password.RequireNonAlphanumeric = false;
                opts.Password.RequireLowercase = false;
                opts.Password.RequireUppercase = false;
                opts.Password.RequireDigit = false;
            
            });

The error is detected by the code and I do get an error message from the framework. However the error message contains verbiage concerning a Role which makes no sense to me. So the error message that gets displayed to the User is in the popup dialog is

"User already in role User name 'xxx xxx' is invalid, allowable characters 'a-z 'A-Z'."

enter image description here

Where and or why there's the ""User already in role " pre-pending to the correct last part of the error message is beyond me.

like image 684
Beachdog Avatar asked Aug 31 '25 20:08

Beachdog


1 Answers

Since you created an extension of the IdentityErroDescriber you must also inform Identity to point in the right direction to your new extension class.

That is achieved by providing with your extension class on identity register like this within your ConfigureServices methon in startup.cs:

services.AddIdentity<AppUser, AppRole>()
        .AddErrorDescriber<CustomIdentityErrorDescriber>(); //<== Here

This way, all errors will be displayed as described in your extension method.

like image 169
Mosia Thabo Avatar answered Sep 04 '25 14:09

Mosia Thabo