-
-
Notifications
You must be signed in to change notification settings - Fork 12
Security
- Summary
- Configuration
- Object Model
- Roles & Claims
- Authentication
- Admin User
- Identity Manager
- Injected Services
Securing the application is about user identity, and authentication and authorization.
Nano provides everything required to effectively manage user identities, and still leveraging full control for customizing polices, claims and roles. The default database created by Nano includes all the required tables, and contains all the technical identity data. This is extended with a custom generic user model during signup.
The DefaultIdentityManager
exposes methods for handling all the interaction with user identities, such as login, signup, change email, etc. The TransientIdentityManager
exposes methods for authentication against non-persisted user identities. This could be through external provider login, or with the built-in administrator user.
NOTE: Without a configured IDataProvider
, the identity features are highly limited. Only Transient operations will be available.
Security contains many models, handling everything from login to change password, or logging in with an external provider. Most are straight forward, and is used as parameter for just one method in the IdentityManager
.
When adding the initial database migration snapshot, models and mappings related to identity is injected. The models are based on Microsoft.AspNetCore.Identity
library.
Normally, you would derive your custom user from the IdentityUser<T>
, when building a store for user identity. This approach is not possible when encapsulating functionality, as the consumer would have to deal with too many factors, such as generic parameters and constraints. By using a composite user model, where the identity and user is separated, Nano is able to manage the identity part without having to worry about custom properties. The Signup methods in Nano automatically links the two tables, and when a CustomUser
is retrieved, the related IdentityUser
data is retrieved as well.
The Security
section of the configuration defines behavior related to authentication and authorization in the application. The section is deserialized into an instance of SecurityOptions
, and injected as dependency during startup, thus available for injection throughout the application.
See Appendix - App Settings for details about the app section and the meaning of the variables.
"Security": {
"TokensExpirationInHours": 24,
"Jwt": {
"IsEnabled": true,
"Issuer": "issuer",
"Audience": "audience",
"PublicKey": null,
"PrivateKey": null,
"ExpirationInMinutes": 60,
"RefreshExpirationInHours": 72
},
"Jwt": {
"IsEnabled": false,
"Secret": null,
},
"User": {
"AdminUsername": "admin",
"AdminPassword": "password",
"AdminEmailAddress": "[email protected]",
"AllowedUserNameCharacters": null,
"DefaultRoles": [
"reader",
"writer",
"service"
]
},
"SignIn": {
"RequireConfirmedEmail": false,
"RequireConfirmedPhoneNumber": false
},
"Lockout": {
"AllowedForNewUsers": true,
"MaxFailedAccessAttempts": 3,
"DefaultLockoutTimeSpan": "00:30:00"
},
"Password": {
"RequireDigit": false,
"RequireNonAlphanumeric": false,
"RequireLowercase": false,
"RequireUppercase": false,
"RequiredLength": 5,
"RequiredUniqueCharacters": 0
},
"ExternalLogins": {
"Google": {
"ClientId": null,
"ClientSecret": "N/A",
"Scopes": [
]
},
"Facebook": {
"AppId": null,
"AppSecret": "N/A",
"Scopes": [
]
},
"Microsoft": {
"TenantId": null,
"ClientId": null,
"ClientSecret": "N/A",
"Scopes": [
]
}
}
}
The identity is associated with the user through a simple foreign key navigation, and is included when the user is queried, by deriving the custom user model from the DefaultEntityUser
.
public class DefaultEntityUser : DefaultEntity
{
[MaxLength(128)]
public virtual string IdentityUserId { get; set; }
[Include]
public virtual IdentityUser IdentityUser { get; set; }
}
This isolates and hides all functionality related to the account of a user, and allows to work solely with the user relevant to the application.
NOTE: All identity email addresses, user names and phone numbers must be unique or null. At least one must not be null.
When mapping the user model, derive the mapping implementation from DefaultEntityUserMapping<TEntity>
. Besides that, mapping is no different than models not having an identity associated.
public class DefaultEntityUserMapping<TEntity> : DefaultEntityMapping<TEntity>
where TEntity : DefaultEntityUser
{
public override void Map(EntityTypeBuilder<TEntity> builder)
{
base.Map(builder);
`
builder
.HasOne(x => x.IdentityUser)
.WithOne()
.IsRequired();
}
}
Name | Type | Description |
---|---|---|
Guest | built-in | Currently, not authorized to do anything. |
Reader | built-in | Authorized to read. |
Writer | built-in | Authorized to read and write |
Service | built-in | Authorized to all services. |
Administrator | built-in | Full access to everything. |
MyRole | custom | Custom role specified during signup or login. |
Name | Type | Description |
---|---|---|
AppId | built-in | The id of the application. Set during logon, and used for supporting multiple refresh tokens. Default value: "Default" |
Id | built-in | The user id. |
built-in | The user's email address. | |
Name | built-in | The username |
MyClaim | custom | Custom claim specified during signup or login. |
Nano supports authenticating with user credentials (username and password), and also using one of the supported external providers.
A successful authentication returns a Nano AccessToken
.
{
"AppId": null,
"UserId": null,
"Token": null,
"ExpireAt": null,
"IsExpired": false,
"RefreshToken": {
"Token": null,
"ExpireAt": null,
"IsExpired": false,
},
}
The jwt-token
contains the following claims and values.
{
"appId": "Default",
"jti": "74ec40fe-bb18-4bd6-8ec5-51b37f9c8a5c",
"sub": "08d9da95-9a3b-4ec6-83b0-fa11da6bae7e",
"name": "[email protected]",
"email": "[email protected]",
"http://schemas.microsoft.com/ws/2008/06/identity/claims/role": [
"service",
"administrator"
],
"nbf": 1111111111,
"exp": 1111111111,
"iss": "development.nano",
"aud": "development.nano"
}
See Controller Authentication for details about how to authenticate with your web application.
It's also possible to authenticate using an api-key, by setting the header x-api-key
with a valid api-key.
Api-keys can be managed through the ``IdentityManager```.
Nano supports the following external providers.
Name | Type | Description |
---|---|---|
Implicit | Google authentication using implicit flow. No token refresh possible. | |
Implicit | Facebook authentication using implicit flow. No token refresh possible. | |
Microsoft | Auth-Code | Microsoft authentication using auth code flow. |
When logging in with an external provider through a single-page-application, Nano finalizes the flow by validating the external response. On successful validation a Nano jwt-token is created, wherein the retrieved external access-token is embedded, should it later be needed to authorize against the external provider.
Scopes for id
, email
and username
should be enabled for external providers.
Nano comes with a built-in administrator, defined in the Security Section, as shown below. The administrator user will be created during start-up, if it doesn't already exist.
The administrator has unrestricted permissions, and may access any part of the application.
"Security": {
"User": {
"AdminUsername": "admin",
"AdminPassword": "<<secret>>",
}
}
The administrator will only be created if IsAuth=True
in the Security Section.
"Security": {
"IsAuth": false,
}
The DefaultIdentityManager
, encapsulates features of Microsoft Identity (UserManager
and SignInManager
), exposes atomic methods for managing user identity, and simplifies using custom user identities, by separating the identity from the user.
The TransientIdentityManager
contains methods for logging in users without having a identity store. This can be used to login transiently using the administrator user defined in the configuration, or by using one of the supported external providers. Transient logins can't be refreshed.
Method | Description |
---|---|
GetUserAsync |
Get a identity user. |
SignInAsync |
Signs in the user. |
SignInExternalAsync |
Signs in a user with external provider login. |
GetExternalProvidersAsync |
Gets all the configured external provider schemes. |
SignInRefreshAsync |
Refreshes the login of a signed-in user. |
SignOutAsync |
Logs out a user. |
SignUpAsync |
Registers a new user. |
SignUpExternalAsync |
Registers a new user using an external login provider. |
RemoveExternalLoginAsync |
Removes the external login of a user. |
SetUsernameAsync |
Sets a username for a user. |
SetPasswordAsync |
Sets a password for a user. |
ResetPasswordAsync |
Resets the password of a user. |
GetPasswordOptions |
Get the password options. |
ChangePasswordAsync |
Changes the password of a user. |
ChangeEmailAsync |
Changes the email address of a user |
ConfirmEmailAsync |
Confirms the email of a user. |
ChangePhoneNumberAsync |
Changes the phone number of a user |
ConfirmPhoneNumberAsync |
Confirms the phone number of a user. |
VerifyCustomTokenAsync |
Verifies a custom token. |
GenerateResetPasswordTokenAsync |
Generates an reset password token for a user. |
GenerateConfirmEmailTokenAsync |
Generates an email confirmation token for a user. |
GenerateChangeEmailTokenAsync |
Generates an change email token for a user. |
GenerateConfirmPhoneNumberTokenAsync |
Generates an phone number confirmation token for a user. |
GenerateChangePhoneNumberTokenAsync |
Generates an change phone number token for a user. |
GenerateCustomTokenAsync |
Generates a custom token for a user. |
GetApiKeysAsync |
Get the api-keys if a user. |
CreateApiKeyAsync |
Create a new api-key |
ValidateApiKeyAsync |
Validate an api-key. |
EditApiKeyAsync |
Edit an api-key. |
RevokeApiKeyAsync |
Revoke an api-key. |
GetRolesAsync |
Get all roles. |
CreateRoleAsync |
Create a new role. |
DeleteRoleAsync |
Delete a role. |
GetUserRolesAsync |
Get the roles associated with a user. |
AssignUserRoleAsync |
Assign a roles to a user. |
RemoveUserRoleAsync |
Remove a role from a user. |
GetUserClaimAsync |
Get the claims of a user. |
GetUserClaimsAsync |
Get a claim of a user. |
AssignUserClaimAsync |
Assign a claim to a user. |
RemoveUserClaimAsync |
Remove a claim from a user. |
GetRoleClaimAsync |
Get a role claim. |
GetRoleClaimsAsync |
Get role claims. |
AssignRoleClaimAsync |
Assign a role claim. |
RemoveRoleClaimAsync |
Remove a role claim. |
CreateUser |
Creates a custom user, and the identity user association. |
DeleteIdentityUser |
Delete the Identity user. |
Method | Description |
---|---|
SignInAdminTransientAsync |
Signs in the admin user, defined in the config security section. |
SignInExternalTransientAsync |
Signs in a use with external login info transiently (no identity backing-store). |
GetExternalProviderLoginData |
Get the external login data from an external provider. Basically, signing in the user, and getting the external token, and other data. |
When building the eventing provider, dependencies related to eventing is configured and initialized.
Nano.Security.SecurityOptions
Nano.Security.BaseIdentityManager
Nano.Security.DefaultIdentityManager
Nano.Security.TransientIdentityManager
For a full list of services and dependencies, see Injected Dependencies