JonPSmith / AuthPermissions.AspNetCore

This library provides extra authorization and multi-tenant features to an ASP.NET Core application.

Home Page:https://www.thereformedprogrammer.net/finally-a-library-that-improves-role-authorization-in-asp-net-core/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

AuthP support for UserNames?

ccnicholls99 opened this issue · comments

If you try to add a UserName to a User in Example3AppAuthSetupData.UsersRolesDefinition, you'll get an exception during the AuthDBContext migration as follows...

"AuthPermissions.BaseCode.CommonCode.AuthPermissionsBadDataException: 'Index X: The user XXXXX didn't have a userId and the IFindUserInfoService couldn't find it either.
XXXXX'"

It appears that the AuthP code is creating IdentityUsers with UserName defaulting to Email but allowing a UserName to be specified for AuthP users in the Bulk Load facility.

As a side issue, the password for new users defaults to the user's email address. Would be better to be able to set a default password from dev settings or in production randomize the initial password and force reset on initial sign-on.

I think the problem is that you have added / changed some of the users in the Bulk Load, but you haven't added the ASP.NET Core individual user account users.

These individual user accounts are added via the StartupServicesIndividualAccountsAddDemoUsers, which looks for the DemoUsers in the appsettings.json file.

Of course, Bulk Loading and auto-adding individual user accounts is only there so that you can easily try the various examples - in a real application these features wouldn't be used.

@ccnicholls99 I encountered the same issue initially. However, AuthP allows you to specify a UniqueUserName value as well as a UserName. The UniqueUserName takes priority and is passed to the FindUserInfoService implementation.
Here is my bulk load:

        public static readonly List<BulkLoadUserWithRolesTenant> UsersWithRolesDefinition = new()
        {
            new ( email: "example1@example.com", userName: "Joe Bloggs", nameof(AppRoles.SysAdmin), uniqueUserName: "example1@example.com"),
            // ...
        };

I think the problem is that you have added / changed some of the users in the Bulk Load, but you haven't added the ASP.NET Core individual user account users.

These individual user accounts are added via the StartupServicesIndividualAccountsAddDemoUsers, which looks for the DemoUsers in the appsettings.json file.

Of course, Bulk Loading and auto-adding individual user accounts is only there so that you can easily try the various examples - in a real application these features wouldn't be used.

Sorry. only just got back around to revisiting this issue.

The code you indicated is....

        public async ValueTask ApplyYourChangeAsync(IServiceProvider scopedServices)
        {     
            var userManager = scopedServices.GetRequiredService<UserManager<IdentityUser>>();
            var config = scopedServices.GetRequiredService<IConfiguration>();
            var demoUsers = config["DemoUsers"];

            if (!string.IsNullOrEmpty(demoUsers))
            {
                foreach (var userEmail in demoUsers.Split(',').Select(x => x.Trim()))
                {
                    //NOTE: The password is the same as the user's Email
                    **await userManager.CheckAddNewUserAsync(userEmail, userEmail);**
                }
            }       
        }

As I mentioned, this code is assuming (a) Demo Users are identified by Email Address and (b) the initial password is set to email address. The problem I see is that the demo accounts in appsettings.json are added based on the email address, yet the code in SeedRolesTenantsUsersIfEmpty that looks up the User Account uses the UniqueUserName as the lookup key. As stated, when username = email address then the lookup works. If not, you get the error I originally pointed out.

"in a real application these features wouldn't be used." - well, actually yes it could be part of an automated site provisioning process that includes pre-defined Demo Accounts.

All this implementation is buried in the core code (AuthPermissions.AspNetCore.StartupServices) so it's hard to see how I can work around it or override it at the moment. Perhaps a better idea might be to allow clients to plug-in their own Account Setup Service to....
(a) Define Identity Users using their own identification policy (Username/Email)
(b) Set initial passwords and/or force reset on first logon
....might already be possible, I haven't gotten that far yet.

hi @ccnicholls99,

I thought about this and I decided the best way is for you create your own code to setup users, which cover below. I only envisioned that Bulk Load code be used to setup the SuperUser when deploying a new application and I think is the best way. That's because the user part of the Bulk Load feature won't work with all the ASP.NET Core authentication providers, while AddRolesPermissionsIfEmpty will always work.

My recommended approaches are to setup the SuperUser when deploying a new application and use AddRolesPermissionsIfEmpty to add the Roles, then use:

1. Manual setup of users - best for adding a few app admin users

You use the admin features to add users manually, either via the normal "Add User" pages etc. (see this article), or use the IAddNewUserManager feature, which is designed to handle any ASP.NET Core authentication provider (see Add New User adapter).

2. Manual invite users - best to add tenant users

There is a "invite a user" feature, where you can define what roles, tenants, etc. and then send invite to a new user. They use the invite log in, and they are ready to go.

Also consider using a "tenant admin" who is in charge of a tenant (see this section in the Administration article), which moves the admin burden to someone in the each tenant).

2. Create code to add users - best for adding lots of users

If you want to add lots users, e.g. adding all the people in a company using the AzureAD authentication provider, then use the AuthUsersAdminService directly to add users. You will be creating the same type of user Bulk Load data, but your code will be focus on your specific needs.