Core Identity JWT
Core Identity JWT
It refers to the
process of confirming the identity of an application’s users. Implementing
it properly could be a hard job if you are not familiar with the process.
Also, it could take a lot of time that could be spent on different features of
an application.
Asp.NET Core Identity is the membership system for web applications that
includes membership, login, and user data. It provides a rich set of
services that help us with creating users, hashing their passwords,
creating a database model, and the authentication overall.
232
After the installation, we are going to create a new User class in the
Entities/Models folder:
Our class inherits from the IdentityUser class that has been provided
by the ASP.NET Core Identity. It contains different properties and we can
extend it with our own as well.
modelBuilder.ApplyConfiguration(new CompanyConfiguration());
modelBuilder.ApplyConfiguration(new EmployeeConfiguration());
}
So, our class now inherits from the IdentityDbContext class and not
DbContext because we want to integrate our context with Identity.
Additionally, we call the OnModelCreating method from the base class.
This is required for migration to work properly.
233
var builder = services.AddIdentityCore<User>(o =>
{
o.Password.RequireDigit = true;
o.Password.RequireLowercase = false;
o.Password.RequireUppercase = false;
o.Password.RequireNonAlphanumeric = false;
o.Password.RequiredLength = 10;
o.User.RequireUniqueEmail = true;
});
services.AddAuthentication();
services.ConfigureIdentity();
app.UseAuthentication();
app.UseAuthorization();
Creating tables is quite an easy process. All we have to do is to create
and apply migration. So, let’s create a migration:
234
PM> Update-Database
Now, let’s insert several roles in the AspNetRoles table, again by using
migrations. The first thing we are going to do is to create the
RoleConfiguration class in the Entities/Configuration folder:
235
And let’s modify the OnModelCreating method in the
RepositoryContext class:
modelBuilder.ApplyConfiguration(new CompanyConfiguration());
modelBuilder.ApplyConfiguration(new EmployeeConfiguration());
modelBuilder.ApplyConfiguration(new RoleConfiguration());
}
PM> Update-Database
If you check the AspNetRoles table, you will find two new roles created.
For this, we have to create a new controller:
[Route("api/authentication")]
[ApiController]
public class AuthenticationController: ControllerBase
{
private readonly ILoggerManager _logger;
private readonly IMapper _mapper;
private readonly UserManager<User> _userManager;
public AuthenticationController (ILoggerManager logger, IMapper mapper,
UserManager<User> userManager)
{
_logger = logger;
_mapper = mapper;
_userManager = userManager;
}
}
So, this is a familiar code except for the UserManager<TUser> part. That
service is provided by Identity and it provides APIs for managing users.
We don’t have to inject our repository here because UserManager
provides us all we need for this example.
236
public class UserForRegistrationDto
{
public string FirstName { get; set; }
public string LastName { get; set; }
[Required(ErrorMessage = "Username is required")]
public string UserName { get; set; }
[Required(ErrorMessage = "Password is required")]
public string Password { get; set; }
public string Email { get; set; }
public string PhoneNumber { get; set; }
public ICollection<string> Roles { get; set; }
}
CreateMap<UserForRegistrationDto, User>();
[HttpPost]
[ServiceFilter(typeof(ValidationFilterAttribute))]
public async Task<IActionResult> RegisterUser([FromBody] UserForRegistrationDto
userForRegistration)
{
var user = _mapper.Map<User>(userForRegistration);
return BadRequest(ModelState);
}
return StatusCode(201);
}
We are implementing our existing action filter for the entity and model
validation on top of our action. After that, we map the DTO object to the
User object and call the CreateAsync method to create that specific user
in the database. The CreateAsync method will save the user to the
database if the action succeeds or it will return error messages. If it
returns error messages, we add them to the model state.
237
Finally, if a user is created, we connect it to its roles — the default one or
the ones sent from the client side — and return 201 created .
https://localhost:5001/api/authentication
And we get 201, which means that the user has been created and added
to the role. We can send additional invalid requests to test our Action and
Identity features.
238
https://localhost:5001/api/authentication
https://localhost:5001/api/authentication
Finally, if we want to create a user with the same user name and email:
https://localhost:5001/api/authentication
Before we get into the implementation of authentication and
authorization, let’s have a quick look at the big picture. There is an
application that has a login form. A user enters its username and
password and presses the login button. After pressing the login button, a
client (e.g., web browser) sends the user’s data to the server’s API
endpoint:
239
When the server validates the user’s credentials and confirms that the
user is valid, it’s going to send an encoded JWT to the client. A JSON web
token is a JavaScript object that can contain some attributes of the
logged-in user. It can contain a username, user subject, user roles, or
some other useful information.
JSON web tokens enable a secure way to transmit data between two
parties in the form of a JSON object. It’s an open standard and it’s a
popular mechanism for web authentication. In our case, we are going to
use JSON web tokens to securely transfer a user’s data between the client
and the server.
JSON web tokens consist of three basic parts: the header, the payload,
and the signature.
Every part of all three parts is shown in a different color. The first part of
JWT is the header, which is a JSON object encoded in the base64 format.
The header is a standard part of JWT and we don’t have to worry about it.
240
It contains information like the type of token and the name of the
algorithm:
{
"alg": "HS256",
"typ": "JWT"
}
{
"sub": "1234567890",
"name": "John Doe",
"iat": 1516239022
}
Finally, we have the signature part. Usually, the server uses the signature
part to verify whether the token contains valid information, the
information which the server is issuing. It is a digital signature that gets
generated by combining the header and the payload. Moreover, it’s based
on a secret key that only the server knows:
So, if malicious users try to modify the values in the payload, they have
to recreate the signature; for that purpose, they need the secret key only
known to the server. At the server side, we can easily verify if the values
241