0% found this document useful (0 votes)
38 views10 pages

Core Identity JWT

The document discusses integrating ASP.NET Core Identity for user authentication into an application. It describes adding the necessary NuGet packages, creating a User class that inherits from IdentityUser, modifying the database context to inherit from IdentityDbContext, and configuring Identity services. It also covers generating the database tables using migrations, adding roles to the AspNetRoles table, and creating an AuthenticationController with a RegisterUser action to register new users and add them to roles.

Uploaded by

AMARA AHMED
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
0% found this document useful (0 votes)
38 views10 pages

Core Identity JWT

The document discusses integrating ASP.NET Core Identity for user authentication into an application. It describes adding the necessary NuGet packages, creating a User class that inherits from IdentityUser, modifying the database context to inherit from IdentityDbContext, and configuring Identity services. It also covers generating the database tables using migrations, adding roles to the AspNetRoles table, and creating an AuthenticationController with a RegisterUser action to register new users and add them to roles.

Uploaded by

AMARA AHMED
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
Download as pdf or txt
Download as pdf or txt
You are on page 1/ 10

User authentication is an important part of any application.

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.

So, in this section, we are going to learn about authentication and


authorization in ASP.NET Core by using Identity and JWT (Json Web
Token). We are going to explain step by step how to integrate Identity in
the existing project and then how to implement JWT for the
authentication and authorization actions.

ASP.NET Core provides us with both functionalities, making


implementation even easier.

So, let’s start with Identity integration.


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.

That said, let’s start with the integration process.

The first thing we have to do is to install the


Microsoft.AspNetCore.Identity.EntityFrameworkCore library in
the Entities project:

232
After the installation, we are going to create a new User class in the
Entities/Models folder:

public class User : IdentityUser


{
public string FirstName { get; set; }
public string LastName { get; set; }
}

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.

After that, we have to modify the RepositoryContext class:

public class RepositoryContext : IdentityDbContext<User>


{
public RepositoryContext(DbContextOptions options)
: base(options)
{
}

protected override void OnModelCreating(ModelBuilder modelBuilder)


{
base.OnModelCreating(modelBuilder);

modelBuilder.ApplyConfiguration(new CompanyConfiguration());
modelBuilder.ApplyConfiguration(new EmployeeConfiguration());
}

public DbSet<Company> Companies { get; set; }


public DbSet<Employee> Employees { get; set; }
}

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.

Now, we have to move on to the configuration part.

To do that, let’s create a new extension method in the


ServiceExtensions class:

public static void ConfigureIdentity(this IServiceCollection services)


{

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;
});

builder = new IdentityBuilder(builder.UserType, typeof(IdentityRole),


builder.Services);
builder.AddEntityFrameworkStores<RepositoryContext>()
.AddDefaultTokenProviders();
}

With the AddIdentityCore method, we are adding and configuring


Identity for the specific type; in this case, the User type. As you can see,
we use different configuration parameters that are pretty self-explanatory
on their own. Identity provides us with even more features to configure,
but these are sufficient for our example.

Then, we create an Identity builder and add EntityFrameworkStores


implementation with the default token providers.

Now, let’s modify the ConfigureServices method:

services.AddAuthentication();
services.ConfigureIdentity();

And, let’s modify the Configure method:

app.UseAuthentication();
app.UseAuthorization();

That’s it. We have prepared everything we need.


Creating tables is quite an easy process. All we have to do is to create
and apply migration. So, let’s create a migration:

PM> Add-Migration CreatingIdentityTables

And then apply it:

234
PM> Update-Database

If we check our database now, we are going to see additional tables:

For our project, the AspNetRoles, AspNetUserRoles, and AspNetUsers


tables will be quite enough. If you open the AspNetUsers table, you will
see additional FirstName and LastName columns.

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:

public class RoleConfiguration : IEntityTypeConfiguration<IdentityRole>


{
public void Configure(EntityTypeBuilder<IdentityRole> builder)
{
builder.HasData(
new IdentityRole
{
Name = "Manager",
NormalizedName = "MANAGER"
},
new IdentityRole
{
Name = "Administrator",
NormalizedName = "ADMINISTRATOR"
}
);
}

235
And let’s modify the OnModelCreating method in the
RepositoryContext class:

protected override void OnModelCreating(ModelBuilder modelBuilder)


{
base.OnModelCreating(modelBuilder);

modelBuilder.ApplyConfiguration(new CompanyConfiguration());
modelBuilder.ApplyConfiguration(new EmployeeConfiguration());
modelBuilder.ApplyConfiguration(new RoleConfiguration());
}

Finally, let’s create and apply migration:

PM> Add-Migration AddedRolesToDb

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.

The next thing we have to do is to create a UserForRegistrationDto


class in the DataTransferObjects folder:

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; }
}

Then, let’s create a mapping rule in the MappingProfile class:

CreateMap<UserForRegistrationDto, User>();

Finally, it is time to create the RegisterUser action:

[HttpPost]
[ServiceFilter(typeof(ValidationFilterAttribute))]
public async Task<IActionResult> RegisterUser([FromBody] UserForRegistrationDto
userForRegistration)
{
var user = _mapper.Map<User>(userForRegistration);

var result = await _userManager.CreateAsync(user, userForRegistration.Password);


if(!result.Succeeded)
{
foreach (var error in result.Errors)
{
ModelState.TryAddModelError(error.Code, error.Description);
}

return BadRequest(ModelState);
}

await _userManager.AddToRolesAsync(user, userForRegistration.Roles);

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 .

If you want, before calling AddToRoleAsync or AddToRolesAsync , you


can check if roles exist in the database. But for that, you have to inject
RoleManager<TRole> and use the RoleExistsAsync method. Now, we
can test this.

Before we continue, we should increase a rate limit from 3 to 30


(ServiceExtensions class, ConfigureRateLimitingOptions method)
just to not stand in our way while we’re testing the different features of
our application.

Let’s send a valid request first:

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.

If the model is invalid:

238
https://localhost:5001/api/authentication

If the password is invalid:

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

Excellent. Everything is working as planned. We can move on to the JWT


implementation.


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.

One real example of a JSON web token:

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"
}

After the header, we have a payload which is also a JavaScript object


encoded in the base64 format. The payload contains some attributes
about the logged-in user. For example, it can contain the user id, the user
subject, and information about whether a user is an admin user or not.
JSON web tokens are not encrypted and can be decoded with any
base64 decoder, so please never include sensitive information in the
Payload:

{
"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

You might also like