-
Notifications
You must be signed in to change notification settings - Fork 162
Invite new user service
Version 3.3.0 of the AuthP library provides a service that allows an existing user (with the right admin Role/Permission) to invite a new user to join the application. This feature, known as "invite a user", provides a quick and secure way to add new users. This feature is especially useful for multi-tenant applications as a tenant admin can invite any colleges join their tenant. It also reduces the load on the app admin users.
NOTE: This section of one of the multi-tenant articles explains the different admin types within a multi-tenant application.
The "invite a user" feature is provided by the IInviteNewUserService
and works with any type of application: normal app, or a multi-tenant app of any type, i.e. single-level, hierarchical and / or sharding and via the add New User adapter it can work with different ASP.NET Core authentication handlers.
Example 3 contains the "invite a user" feature which uses individual user accounts authenticate. Example 5 has the "invite a user" feature, but linking to Azure AD for authenticate.
The "invite a user" feature uses two services in the AuthPermissions.SupportCode namespace.
- The
IInviteNewUserService
\InviteNewUserService
, which implements the "invite a user" service. - The
IAddNewUserManager
service which theInviteNewUserService
relies on for adding a new user (see Add New User adapter for more details).
Any code in the AuthPermissions.SupportCode
project has to be manually, and the code shown below is taken from Example 3 during the registering of the service to use in your ASP.NET Core application.
//Add the SupportCode services
services.AddTransient<IAddNewUserManager, IndividualUserAddUserManager<IdentityUser>>();
services.AddTransient<ISignInAndCreateTenant, SignInAndCreateTenant>();
Note that the IAddNewUserManager
service uses an implementation called IndividualUserAddUserManager<IdentityUser>
which works with applications using the individual user accounts authenticate provider. Version 3.3.0 only contains two implementations of the IAddNewUserManager
interface. They are:
-
IndividualUserAddUserManager<TIdentity>
which works with the individual user accounts authenticate provider. -
AzureAdUserManager
which works with Azure AD authenticate provider (NOTE: won't work with Azure AD B2C with social logins).
More implementations may be added, or you can build your own by implementing the IAddNewUserManager
interface.
Typically some sort of admin user can create an invite - this is controlled by adding a Permission to the Razor Page, Controller actions or Web API that creates the invite. When creating an invite you need three things:
- Email: This ensures only the person with that email can use the created invite
- Roles: This allows the admin to define what roles the new user will have.
-
TenantId: If the application is multi-tenant this defines want tenant it will be linked to. What value that the
TenantId
can be set to depends on what type of admin user is creating the invite- If its a single-level multi-tenant and the user is a tenant admin, then you don't have to set the
TenantId
as the tenant admin'sTenantId
is used - If its a hierarchical multi-tenant and the user is a tenant admin, then you must set the
TenantId
with a tenant value that is within your group tenant's that you control. - If the user is an app admin, then you can:
- Set it to a Tenant value, which will make the invited user is linked to that tenant
- Set it to null, which will make the invited user NOT linked to a tenant - useful for adding app admin or customer support users.
- If its a single-level multi-tenant and the user is a tenant admin, then you don't have to set the
- Expiration: Version 3.4.0 added a expiration time on the invite. The screenshot below shows the default range of expiration times, but you can create your own range.
Here is an example of a single-level multi-tenant application where you define the new user's email and Roles (the TenantId is automatically taken from the tenant admin).
And here is a code within the Example 3's TenantAdminController
[HasPermission(Example3Permissions.InviteUsers)]
public async Task<ActionResult> InviteUser([FromServices]IAuthTenantAdminService rolesAdmin)
{
var setupInvite = new InviteUserSetup
{
AllRoleNames = await _authUsersAdmin.GetRoleNamesForUsersAsync(User.GetUserIdFromUser())
};
return View(setupInvite);
}
[HasPermission(Example3Permissions.InviteUsers)]
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> InviteUser([FromServices] IInviteNewUserService inviteUserServiceService,
InviteUserSetup data)
{
var addUserData = new AddNewUserDto { Email = data.Email, Roles = data.RoleNames
TimeInviteExpires = data.InviteExpiration};
var status = await inviteUserServiceService
.CreateInviteUserToJoinAsync(addUserData, User.GetUserIdFromUser());
if (status.HasErrors)
return RedirectToAction(nameof(ErrorDisplay),
new { errorMessage = status.GetAllErrors() });
var inviteUrl = AbsoluteAction(Url, nameof(HomeController.AcceptInvite),
"Home", new { verify = status.Result });
return View("InviteUserUrl", new InviteUserResult( status.Message, inviteUrl));
}
//Thanks to https://stackoverflow.com/questions/30755827/getting-absolute-urls-using-asp-net-core
public string AbsoluteAction(IUrlHelper url,
string actionName,
string controllerName,
object routeValues = null)
{
string scheme = HttpContext.Request.Scheme;
return url.Action(actionName, controllerName, routeValues, scheme);
}
On clicking the Create Invite button it will return a URL containing the new user's settings in an encrypted parameter called verify - see this example in the screenshot below. Note that if you set a expiration time, then the message tells you went it will expires.
This should be sent to the invited user.
The previous step created a URL for the invited user. This should be linked to a action / page which can be accessed by a user who isn't logged in.The invited user then has to provide their email, which is checked against the encrypted settings (this stops a invite by being used by another user). Depending on the type of authentication provider you are using you might need to provide a password (Azure AD version creates a temporary password for the first login, where you are asked to replace with password only known to you). The screenshot below shows the Example 3 version.
The code from Example 3 to register the new user is shown below
[AllowAnonymous]
public ActionResult AcceptInvite(string verify)
{
return View(new AcceptInviteDto { Verify = verify });
}
[AllowAnonymous]
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> AcceptInvite(
[FromServices] IInviteNewUserService inviteUserServiceService,
string verify, string email, string userName, string password)
{
var status = await inviteUserServiceService.AddUserViaInvite(verify, email, null, password);
if (status.HasErrors)
return RedirectToAction(nameof(ErrorDisplay),
new { errorMessage = status.GetAllErrors() });
return RedirectToAction(nameof(Index),
new { message = status.Message });
}
- Intro to multi-tenants (ASP.NET video)
- Articles in date order:
- 0. Improved Roles/Permissions
- 1. Setting up the database
- 2. Admin: adding users and tenants
- 3. Versioning your app
- 4. Hierarchical multi-tenant
- 5. Advanced technique with claims
- 6. Sharding multi-tenant setup
- 7. Three ways to add new users
- 8. The design of the sharding data
- 9. Down for maintenance article
- 10: Three ways to refresh claims
- 11. Features of Multilingual service
- 12. Custom databases - Part1
- Videos (old)
- Authentication explained
- Permissions explained
- Roles explained
- AuthUser explained
- Multi tenant explained
- Sharding explained
- How AuthP handles sharding
- How AuthP handles errors
- Languages & cultures explained
- JWT Token refresh explained
- Setup Permissions
- Setup Authentication
- Startup code
- Setup the custom database feature
- JWT Token configuration
- Multi tenant configuration
- Using Permissions
- Using JWT Tokens
- Creating a multi-tenant app
- Supporting multiple languages
- Unit Test your AuthP app