Authentication
Bulletcode.NET extends the built-in authentication mechanism in ASP.NET Core. It provides support for cookie and JWT bearer authentication schemes based on local users, and implements a simple API key authentication scheme.
The simplest way to restrict access to a controller or a particular action is by using the Authorize
attribute with the AuthenticationSchemes
property. The AuthenticationConstants
class defines the names of schemes defined by Bulletcode.NET: UserCookieScheme
, UserTokenScheme
and ApiKeyScheme
. The UserSchemes
constant includes both cookie and token authentication schemes.
NOTE
When more granular access control is required to authorize permissions for individual actions, you can use the role-based authorization mechanism implemented by Bulletcode.NET. See the Authorization chapter for more information.
Local users
Both cookie and JWT bearer authentication schemes implemented by Bulletcode.NET are based on user entities which are stored in the application’s database and authenticated using a hashed password.
In order to use either of these authentication schemes, the application must define a database context which inherits CoreDbContext
, as described in the Database chapter. The built-in User
database entity stores the user information, and the IUserService
provides methods for retrieving, adding, updating and deleting user entities.
The application can inherit the User
class and add custom properties. In this case, it can also override the built-in IUserClaimsFactory<TUser>
service in order to store additional user information in the ClaimsPrincipal
object which is stored in the cookie or the JWT token.
The default implementation of this service stores the user’s ID, display name (which defaults to the user’s email, unless overridden in the custom User
class), email, role and authentication key. The authentication key is a random value which is updated whenever the user’s password is changed, so that all existing cookies and tokens can be invalidated.
Bulletcode.NET implements the following extension methods which extend the ClaimsPrincipal
object:
FindUserId()
— returns the user’s ID as an integer value; this value is stored in theClaimTypes.NameIdentifier
claim.FindRole()
— returns the user’s role; this value is stored in theClaimTypes.Role
claim.
Cookie authentication
The cookie authentication scheme in Bulletcode.NET is based on the built-in support for cookie authentication in ASP.NET Core. Call the AddUserCookie<TUser>()
extension method to enable it:
services
.AddAuthentication( AuthenticationConstants.UserCookieScheme )
.AddUserCookie<User>();
In the example above, the user cookie scheme is also configured as the default authentication scheme. The built-in User
class is passed as a template parameter to the AddUserCookie()
method, but if your application implements a custom user entity which inherits User
, it should be passed instead.
The UserCookieOptions
class contains options for cookie authentication. They can be changed by passing a callback to the AddUserCookie()
method, or by adding a UserCookie
subsection in the Authentication
section of the appsettings.json
file.
LoginPath
— the path of the login page. If not set, the default"/Account/Login"
is used.CookieName
— the name of the cookie storing user’s identify. The default value is".BC.User"
.ExpireTimeSpan
— the expiration time of the cookie. The default value is 2 hours.PersistentExpireTimeSpan
— the expiration time of the cookie when the “remember me” option is selected. The default value is 14 days.ValidationTimeSpan
— the interval at which the validity of the cookie is verified by querying the database. The default value is 5 minutes.TokenExpireTimeSpan
— the lifetime of the token which can be used to reset the user’s password. The default value is 8 hours.
Bulletcode.NET uses the ICookieHandler
service to implement custom event handlers for the cookie authentication events. The default implementation of this service validates that the user exists in the database and the authentication key matches the one stored in the cookie, and recreates the cookie is the principal is still valid. It also returns an error in JSON format when a REST API call is detected, instead of redirecting to the login page (see the Diagnostics chapter).
NOTE
Both the challenge and the forbid handler for cookie authentication return a 403 status code when a REST API call is detected, because a 401 status code can only be used with the WWW-Authenticate
header, and doesn’t make sense for cookie authentication. In order to authorize access to the REST API, the token authentication scheme, described below, should be used instead.
The application should use the IAccountService<TUser>
service to manage user cookies and to change or reset user passwords. The TUser
parameter should be the built-in User
class, or a custom class which inherits it. This service contains the following methods:
SignInAsync()
— checks if the email and password are valid and generates a user cookie. Returnsfalse
if the email or password is invalid.SignOutAsync()
— destroys the user cookie.ChangePasswordAsync()
— checks if the current password is valid and sets a new password. Returnsfalse
if the user is not logged in or the current password is invalid.RequestResetPasswordAsync()
— generates a token for resetting the password for the specified user. Returnsnull
if the user doesn’t exist. After calling this method, the application should send an email containing a link with the token.IsPasswordResetTokenValidAsync()
— returnstrue
if the specified password reset token is valid.ResetPasswordAsync()
— sets a new password for a user associated with the specified password reset token.RefreshSignInAsync()
— creates a new cookie for the currently logged in user. This method is automatically called byChangePasswordAsync()
so that the user remains logged in.
Since cookie authentication relies on the built-in mechanism in ASP.NET Core, the user cookies are encrypted using the built-in data protection mechanism.
The IUserClaimsFactory<TUser>
service (see above) is used to generate claims stored in the user cookie.
Token authentication
The token authentication scheme in Bulletcode.NET is based on the built-in support for JWT bearer authentication is ASP.NET core. Call the AddUserToken<TUser>()
extension method to enable it:
services
.AddAuthentication( AuthenticationConstants.UserCookieScheme )
.AddUserCookie<User>()
.AddUserToken<User>();
The token authentication scheme is typically used with a REST API. The API should implement a method which authenticates a user based on the email and password and returns a token, and a method which can be used to keep the session alive by creating a new token based on the existing one. See the API Client chapter for more information about storing and refreshing the token in client applications.
The UserTokenOptions
class contains options for token authentication. They can be changed by passing a callback to the AddUserToken()
method, or by adding a UserToken
subsection in the Authentication
section of the appsettings.json
file.
SigningKey
— the key for signing the token.EncryptingKey
— the key for encrypting the token.ExpireTimeSpan
— the expiration time of the token. The default value is 1 hour.Realm
— the realm name for theWWW-Authenticate
header. The default value is the request’s host name.
WARNING
Make sure that you don’t use the same SigningKey
and EncryptingKey
in your production environment as the default keys used in development environment. Both keys should be random strings containing 32 or more characters.
Bulletcode.NET users the IJwtBearerHandler
service to implement custom event handlers for the JWT bearer authentication events. The default implementation sets the WWW-Authenticate
header and returns an error in JSON format when a REST API call is detected.
The application should use the ITokenService<TUser>
to create and refresh tokens. The TUser
parameter should be the built-in User
class, or a custom class which inherits it. This service contains the following methods:
AuthenticateAsync()
checks if the email and password are valid and generates a user token. Returnsnull
if the email or password is invalid.RefreshTokenAsync()
creates a new token for the currently logged in user.
The JWT token created by the token authentication scheme does not contain an issuer or audience information. It is validated by using the signing key. The token is also encrypted so that user information cannot be extracted from it.
The IUserClaimsFactory<TUser>
service (see above) is used to generate claims stored in the JWT token.
API key authentication
The API key authentication scheme is a simple authentication mechanism using a fixed bearer token.
Call the AddApiKey()
extension method to enable API key authentication:
services
.AddAuthentication()
.AddApiKey();
The ApiKeyAuthenticationOptions
class contains options for API key authentication. They can be changed by passing a callback to the AddApiKey()
method, or by adding an ApiKey
subsection in the Authentication
section of the appsettings.json
file:
ApiKey
- the value of the API key.Realm
— the realm name for theWWW-Authenticate
header. The default value is the request’s host name.
WARNING
Make sure that you don’t use the same API key in your production environment as the default keys used in development environment.
The API key can be used to protect access for operations which are executed remotely, such as running cron jobs, to guard the application against DoS attacks. However, it should not be used for protecting sensitive information.
Bulletcode.NET uses the ApiKeyAuthenticationHandler
class to implement API key authentication. The application can customize the validation, challenge and forbidden event handlers. The default event handlers create an empty claims principal with the AuthenticationConstants.ApiKeyScheme
when the bearer token in the request matches the configured API key value, or set the WWW-Authenticate
header and return an error in JSON format when a REST API call is detected.