INFO
When using ASP.NET Core Identity Auth refer to Identity Auth Admin Users UI instead
The User Admin Plugin is a lightweight API for providing user management functionality around Auth Repository APIs and enables remote programmatic access to manage your registered User Auth Repository, featuring:
- Works with existing
IUserAuthRepository
sync or async providers - Utilizes Progressive enhancement, e.g. search functionality utilizes
IQueryUserAuth
(if exists) performing a wildcard search over multiple fields, otherwise falls back to exact match onUserName
orEmail
- Supports managing Auth Repositories utilizing custom
UserAuth
data models - Flexible UI options for customizing which fields to include in Search Results and Create/Edit UIs
- Rich Metadata aggregating only App-specific Roles & Permissions defined in your App
- User Events allow you to execute custom logic before & after each Created/Updated/Deleted User
Installation​
The AdminUsersFeature
plugin contains no additional dependencies that at a minimum can be registered with:
Plugins.Add(new AdminUsersFeature());
INFO
An IAuthRepository
is a required registered dependency to be able to use the AdminUsersFeature
plugin.
Managing Users​
By default, the Add and Edit Users forms contains the default layout of common properties in UserAuth.cs
Customization​
To customize this user interface to accommodate custom properties, the UserFormLayout
needs to be overridden.
For example, below we have a custom UserAuth
called AppUser
with additional properties.
// Custom User Table with extended Metadata properties
public class AppUser : UserAuth
{
public Department Department { get; set; }
public string? ProfileUrl { get; set; }
public string? LastLoginIp { get; set; }
public bool IsArchived { get; set; }
public DateTime? ArchivedDate { get; set; }
public DateTime? LastLoginDate { get; set; }
}
public enum Department
{
None,
Marketing,
Accounts,
Legal,
HumanResources,
}
The AdminUsersFeature
has multiple fiends that can be used to customize the UI including.
Property Name | Description |
---|---|
QueryUserAuthProperties |
Columns visible in query results for users. |
QueryMediaRules |
Which columns start appearing at different screen sizes. |
UserFormLayout |
Control which fields are used for Create/Edit and their placement. |
Custom User Form Layout​
Similar to the API Explorer FormLayout
customization, UserFormLayout
is used to control placement and details about individual fields.
appHost.Plugins.Add(new ServiceStack.Admin.AdminUsersFeature {
// Show custom fields in Search Results
QueryUserAuthProperties = new() {
nameof(AppUser.Id),
nameof(AppUser.Email),
nameof(AppUser.DisplayName),
nameof(AppUser.Department),
nameof(AppUser.CreatedDate),
nameof(AppUser.LastLoginDate),
},
QueryMediaRules = new()
{
MediaRules.ExtraSmall.Show<AppUser>(x => new { x.Id, x.Email, x.DisplayName }),
MediaRules.Small.Show<AppUser>(x => x.Department),
},
// Add Custom Fields to Create/Edit User Forms
FormLayout = new() {
Input.For<AppUser>(x => x.Email, x => x.Type = Input.Types.Email),
Input.For<AppUser>(x => x.DisplayName),
Input.For<AppUser>(x => x.UserName),
Input.For<AppUser>(x => x.Company, c => c.FieldsPerRow(2)),
Input.For<AppUser>(x => x.Department, c => c.FieldsPerRow(2)),
Input.For<AppUser>(x => x.PhoneNumber, c => c.Type = Input.Types.Tel),
Input.For<AppUser>(x => x.Nickname, c => {
c.Help = "Public alias (3-12 lower alpha numeric chars)";
c.Pattern = "^[a-z][a-z0-9_.-]{3,12}$";
}),
Input.For<AppUser>(x => x.ProfileUrl, c => c.Type = Input.Types.Url),
Input.For<AppUser>(x => x.IsArchived, c => c.FieldsPerRow(2)),
Input.For<AppUser>(x => x.ArchivedDate, c => c.FieldsPerRow(2)),
}
});
Enabling the use of custom properties as well as formatting for ease of use. UserFormLayout
updates the Create
and Edit
screens in the Admin UI.
Admin User Services​
The Admin User back-end APIs themselves can also be used to manage users within your own Apps.
All the Admin Users DTOs below contains everything needed to call its APIs from .NET Service Clients which are all contained within ServiceStack.Client so no additional dependencies are needed.
The APIs are fairly straight-forward with each DTO containing on the bare minimum Typed properties with all other UserAuth fields you want updated in the UserAuthProperties
Dictionary. Whilst all User result-sets are returned in an unstructured Object Dictionary.
public abstract class AdminUserBase : IMeta
{
public string UserName { get; set; }
public string FirstName { get; set; }
public string LastName { get; set; }
public string DisplayName { get; set; }
public string Email { get; set; }
public string Password { get; set; }
public string ProfileUrl { get; set; }
public Dictionary<string, string> UserAuthProperties { get; set; }
public Dictionary<string, string> Meta { get; set; }
}
public partial class AdminCreateUser : AdminUserBase, IPost, IReturn<AdminUserResponse>
{
public List<string> Roles { get; set; }
public List<string> Permissions { get; set; }
}
public partial class AdminUpdateUser : AdminUserBase, IPut, IReturn<AdminUserResponse>
{
public string Id { get; set; }
public bool? LockUser { get; set; }
public bool? UnlockUser { get; set; }
public List<string> AddRoles { get; set; }
public List<string> RemoveRoles { get; set; }
public List<string> AddPermissions { get; set; }
public List<string> RemovePermissions { get; set; }
}
public partial class AdminGetUser : IGet, IReturn<AdminUserResponse>
{
public string Id { get; set; }
}
public partial class AdminDeleteUser : IDelete, IReturn<AdminDeleteUserResponse>
{
public string Id { get; set; }
}
public class AdminDeleteUserResponse : IHasResponseStatus
{
public string Id { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
public partial class AdminUserResponse : IHasResponseStatus
{
public string Id { get; set; }
public Dictionary<string,object> Result { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}
public partial class AdminQueryUsers : IGet, IReturn<AdminUsersResponse>
{
public string Query { get; set; }
public string OrderBy { get; set; }
public int? Skip { get; set; }
public int? Take { get; set; }
}
public class AdminUsersResponse : IHasResponseStatus
{
public List<Dictionary<string,object>> Results { get; set; }
public ResponseStatus ResponseStatus { get; set; }
}