The first thing that comes to mind when building an API is how to secure it. When you think of security, two words immediately spring to mind: authentication and authorization. Authentication is the process of determining whether or not a user is a valid member of the system. Authorization signifies that the member has the authority to carry out the following action.
JWT
JWT and API security go hand in hand. JWT means Json web token. It is used as an authentication or authorization token for your API.
It is like a Gate pass, which allows API to open a gate for the user or block him outside.
We can use the JWT token with our custom authentication and authorization mechanism, or we can use an identity that provides a built-in function to use for general use case.
We will try to secure our application through .Net Identity.
ASP .Net Identity
First, create the new Web API Project.
Add the following NuGet Package.
- Microsoft.AspNetCore.Identity.EntityFrameworkCore
- Microsoft.Extensions.Identity.Core
- Microsoft.Extensions.Identity.Stores
We will be extending the Identity User with some custom property.
1 2 3 4 | <span class="token keyword keyword-public">public</span> <span class="token keyword keyword-class">class</span> <span class="token class-name">User</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">IdentityUser</span></span> <span class="token punctuation">{</span> <span class="token keyword keyword-public">public</span> <span class="token return-type class-name"><span class="token keyword keyword-string">string</span></span> UserType <span class="token punctuation">{</span> <span class="token keyword keyword-get">get</span><span class="token punctuation">;</span> <span class="token keyword keyword-set">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Now we need to create the Identities in our Database and create an Identity Context
We will be renaming the Identity table also.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | <span class="token keyword keyword-public">public</span> <span class="token keyword keyword-class">class</span> <span class="token class-name">FOAContext</span> <span class="token punctuation">:</span> <span class="token type-list"><span class="token class-name">IdentityDbContext<span class="token punctuation"><</span>IdentityUser<span class="token punctuation">></span></span></span> <span class="token punctuation">{</span> <span class="token keyword keyword-public">public</span> <span class="token function">FOAContext</span><span class="token punctuation">(</span><span class="token class-name">DbContextOptions<span class="token punctuation"><</span>FOAContext<span class="token punctuation">></span></span> options<span class="token punctuation">)</span> <span class="token punctuation">:</span> <span class="token keyword keyword-base">base</span><span class="token punctuation">(</span>options<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span> <span class="token keyword keyword-protected">protected</span> <span class="token keyword keyword-override">override</span> <span class="token return-type class-name"><span class="token keyword keyword-void">void</span></span> <span class="token function">OnModelCreating</span><span class="token punctuation">(</span><span class="token class-name">ModelBuilder</span> modelBuilder<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword keyword-base">base</span><span class="token punctuation">.</span><span class="token function">OnModelCreating</span><span class="token punctuation">(</span>modelBuilder<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Override default AspNet Identity table names</span> modelBuilder<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Entity</span><span class="token generic class-name"><span class="token punctuation"><</span>IdentityUser<span class="token punctuation">></span></span></span><span class="token punctuation">(</span>entity <span class="token operator">=></span> <span class="token punctuation">{</span> entity<span class="token punctuation">.</span><span class="token function">ToTable</span><span class="token punctuation">(</span><span class="token named-parameter punctuation">name</span><span class="token punctuation">:</span> <span class="token string">"Users"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> modelBuilder<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Entity</span><span class="token generic class-name"><span class="token punctuation"><</span>IdentityRole<span class="token punctuation">></span></span></span><span class="token punctuation">(</span>entity <span class="token operator">=></span> <span class="token punctuation">{</span> entity<span class="token punctuation">.</span><span class="token function">ToTable</span><span class="token punctuation">(</span><span class="token named-parameter punctuation">name</span><span class="token punctuation">:</span> <span class="token string">"Roles"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> modelBuilder<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Entity</span><span class="token generic class-name"><span class="token punctuation"><</span>IdentityUserRole<span class="token punctuation"><</span><span class="token keyword keyword-string">string</span><span class="token punctuation">></span><span class="token punctuation">></span></span></span><span class="token punctuation">(</span>entity <span class="token operator">=></span> <span class="token punctuation">{</span> entity<span class="token punctuation">.</span><span class="token function">ToTable</span><span class="token punctuation">(</span><span class="token string">"UserRoles"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> modelBuilder<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Entity</span><span class="token generic class-name"><span class="token punctuation"><</span>IdentityUserClaim<span class="token punctuation"><</span><span class="token keyword keyword-string">string</span><span class="token punctuation">></span><span class="token punctuation">></span></span></span><span class="token punctuation">(</span>entity <span class="token operator">=></span> <span class="token punctuation">{</span> entity<span class="token punctuation">.</span><span class="token function">ToTable</span><span class="token punctuation">(</span><span class="token string">"UserClaims"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> modelBuilder<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Entity</span><span class="token generic class-name"><span class="token punctuation"><</span>IdentityUserLogin<span class="token punctuation"><</span><span class="token keyword keyword-string">string</span><span class="token punctuation">></span><span class="token punctuation">></span></span></span><span class="token punctuation">(</span>entity <span class="token operator">=></span> <span class="token punctuation">{</span> entity<span class="token punctuation">.</span><span class="token function">ToTable</span><span class="token punctuation">(</span><span class="token string">"UserLogins"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> modelBuilder<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Entity</span><span class="token generic class-name"><span class="token punctuation"><</span>IdentityUserToken<span class="token punctuation"><</span><span class="token keyword keyword-string">string</span><span class="token punctuation">></span><span class="token punctuation">></span></span></span><span class="token punctuation">(</span>entity <span class="token operator">=></span> <span class="token punctuation">{</span> entity<span class="token punctuation">.</span><span class="token function">ToTable</span><span class="token punctuation">(</span><span class="token string">"UserTokens"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> modelBuilder<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Entity</span><span class="token generic class-name"><span class="token punctuation"><</span>IdentityRoleClaim<span class="token punctuation"><</span><span class="token keyword keyword-string">string</span><span class="token punctuation">></span><span class="token punctuation">></span></span></span><span class="token punctuation">(</span>entity <span class="token operator">=></span> <span class="token punctuation">{</span> entity<span class="token punctuation">.</span><span class="token function">ToTable</span><span class="token punctuation">(</span><span class="token string">"RoleClaims"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-public">public</span> <span class="token return-type class-name">DbSet<span class="token punctuation"><</span>User<span class="token punctuation">></span></span> Users <span class="token punctuation">{</span> <span class="token keyword keyword-get">get</span><span class="token punctuation">;</span> <span class="token keyword keyword-set">set</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Now Add the connection string in the appSetting.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token punctuation">{</span> <span class="token string">"ConnectionStrings"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">"AppDb"</span><span class="token punctuation">:</span> <span class="token string">"Data Source=databasename;Initial Catalog=FOADB;User Id=username; Password=password;Integrated Security=True;TrustServerCertificate=True"</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">"Logging"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">"LogLevel"</span><span class="token punctuation">:</span> <span class="token punctuation">{</span> <span class="token string">"Default"</span><span class="token punctuation">:</span> <span class="token string">"Information"</span><span class="token punctuation">,</span> <span class="token string">"Microsoft.AspNetCore"</span><span class="token punctuation">:</span> <span class="token string">"Warning"</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span><span class="token punctuation">,</span> <span class="token string">"AllowedHosts"</span><span class="token punctuation">:</span> <span class="token string">"*"</span> <span class="token punctuation">}</span> |
Now we need to define the identity of the program.cs.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | <span class="token class-name"><span class="token keyword keyword-var">var</span></span> builder <span class="token operator">=</span> WebApplication<span class="token punctuation">.</span><span class="token function">CreateBuilder</span><span class="token punctuation">(</span>args<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Add services to the container.</span> builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token function">AddControllers</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Database connection</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> connectionString <span class="token operator">=</span> builder<span class="token punctuation">.</span>Configuration<span class="token punctuation">.</span><span class="token function">GetConnectionString</span><span class="token punctuation">(</span><span class="token string">"AppDb"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddDbContext</span><span class="token generic class-name"><span class="token punctuation"><</span>FOAContext<span class="token punctuation">></span></span></span><span class="token punctuation">(</span>x <span class="token operator">=></span> x<span class="token punctuation">.</span><span class="token function">UseSqlServer</span><span class="token punctuation">(</span>connectionString<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// For Identity</span> builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddIdentity</span><span class="token generic class-name"><span class="token punctuation"><</span>User<span class="token punctuation">,</span> IdentityRole<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token generic-method"><span class="token function">AddEntityFrameworkStores</span><span class="token generic class-name"><span class="token punctuation"><</span>FOAContext<span class="token punctuation">></span></span></span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">.</span><span class="token function">AddDefaultTokenProviders</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle</span> builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token function">AddEndpointsApiExplorer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token function">AddSwaggerGen</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> app <span class="token operator">=</span> builder<span class="token punctuation">.</span><span class="token function">Build</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Configure the HTTP request pipeline.</span> <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>app<span class="token punctuation">.</span>Environment<span class="token punctuation">.</span><span class="token function">IsDevelopment</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> app<span class="token punctuation">.</span><span class="token function">UseSwagger</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">UseSwaggerUI</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> app<span class="token punctuation">.</span><span class="token function">UseHttpsRedirection</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">UseAuthorization</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">MapControllers</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> app<span class="token punctuation">.</span><span class="token function">Run</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> |
Now run the migration by following the command.
“add-migration Initial”
Now update the database
“update-database”
We now need to implement registration and login flow.
Let’s create a Registration flow first. Create a Register API.
I am using CQRS architecture, but you can design your API as you want.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">HttpPost</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"Register"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">ProducesResponseType</span><span class="token attribute-arguments"><span class="token punctuation">(</span>StatusCodes<span class="token punctuation">.</span>Status200OK<span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token keyword keyword-public">public</span> <span class="token keyword keyword-async">async</span> <span class="token return-type class-name">Task<span class="token punctuation"><</span>ActionResult<span class="token punctuation">></span></span> <span class="token function">Register</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">FromBody</span></span><span class="token punctuation">]</span> <span class="token class-name">RegisterCommandRequest</span> command<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword keyword-try">try</span> <span class="token punctuation">{</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> result <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> _mediator<span class="token punctuation">.</span><span class="token function">Send</span><span class="token punctuation">(</span>command<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword keyword-return">return</span> <span class="token function">Ok</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-catch">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword keyword-return">return</span> <span class="token function">BadRequest</span><span class="token punctuation">(</span>ex<span class="token punctuation">.</span>Message<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> |
Now create a static class with User Roles. We will use this in the registration flow and also when creating a claim during login.
1 2 3 4 5 | <span class="token keyword keyword-public">public</span> <span class="token keyword keyword-static">static</span> <span class="token keyword keyword-class">class</span> <span class="token class-name">UserRoles</span> <span class="token punctuation">{</span> <span class="token keyword keyword-public">public</span> <span class="token keyword keyword-const">const</span> <span class="token class-name"><span class="token keyword keyword-string">string</span></span> Admin <span class="token operator">=</span> <span class="token string">"Admin"</span><span class="token punctuation">;</span> <span class="token keyword keyword-public">public</span> <span class="token keyword keyword-const">const</span> <span class="token class-name"><span class="token keyword keyword-string">string</span></span> User <span class="token operator">=</span> <span class="token string">"User"</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Now we will create the user through Identity User Manager if it does not exist already and will assign the role to it.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | <span class="token keyword keyword-private">private</span> <span class="token keyword keyword-readonly">readonly</span> <span class="token class-name">UserManager<span class="token punctuation"><</span>IdentityUser<span class="token punctuation">></span></span> _userManager<span class="token punctuation">;</span> <span class="token keyword keyword-public">public</span> <span class="token function">RegisterCommandHandler</span><span class="token punctuation">(</span><span class="token class-name">UserManager<span class="token punctuation"><</span>IdentityUser<span class="token punctuation">></span></span> userManager <span class="token punctuation">)</span> <span class="token punctuation">{</span> _userManager <span class="token operator">=</span> userManager<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-public">public</span> <span class="token keyword keyword-async">async</span> <span class="token return-type class-name">Task<span class="token punctuation"><</span>RegisterCommandResponse<span class="token punctuation">></span></span> <span class="token function">Handle</span><span class="token punctuation">(</span><span class="token class-name">RegisterCommandRequest</span> request<span class="token punctuation">,</span> <span class="token class-name">CancellationToken</span> cancellationToken<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> userExists <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> _userManager<span class="token punctuation">.</span><span class="token function">FindByNameAsync</span><span class="token punctuation">(</span>request<span class="token punctuation">.</span>Username<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>userExists <span class="token operator">!=</span> <span class="token keyword keyword-null">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword keyword-throw">throw</span> <span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">ApplicationException</span><span class="token punctuation">(</span><span class="token string">"User already exist"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token class-name">IdentityUser</span> user <span class="token operator">=</span> <span class="token keyword keyword-new">new</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> Email <span class="token operator">=</span> request<span class="token punctuation">.</span>Email<span class="token punctuation">,</span> SecurityStamp <span class="token operator">=</span> Guid<span class="token punctuation">.</span><span class="token function">NewGuid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">,</span> UserName <span class="token operator">=</span> request<span class="token punctuation">.</span>Username <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> result <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> _userManager<span class="token punctuation">.</span><span class="token function">CreateAsync</span><span class="token punctuation">(</span>user<span class="token punctuation">,</span> request<span class="token punctuation">.</span>Password<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span><span class="token operator">!</span>result<span class="token punctuation">.</span>Succeeded<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword keyword-throw">throw</span> <span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">ApplicationException</span><span class="token punctuation">(</span><span class="token string">"User creation failed"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>request<span class="token punctuation">.</span>Userrole <span class="token operator">==</span> UserRoles<span class="token punctuation">.</span>Admin<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword keyword-await">await</span> _userManager<span class="token punctuation">.</span><span class="token function">AddToRoleAsync</span><span class="token punctuation">(</span>user<span class="token punctuation">,</span> UserRoles<span class="token punctuation">.</span>Admin<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-else">else</span> <span class="token punctuation">{</span> <span class="token keyword keyword-await">await</span> _userManager<span class="token punctuation">.</span><span class="token function">AddToRoleAsync</span><span class="token punctuation">(</span>user<span class="token punctuation">,</span> UserRoles<span class="token punctuation">.</span>User<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> registerResponse <span class="token operator">=</span> FOAMapper<span class="token punctuation">.</span>Mapper<span class="token punctuation">.</span><span class="token generic-method"><span class="token function">Map</span><span class="token generic class-name"><span class="token punctuation"><</span>RegisterCommandResponse<span class="token punctuation">></span></span></span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">;</span> registerResponse<span class="token punctuation">.</span>UserRole <span class="token operator">=</span> request<span class="token punctuation">.</span>Userrole<span class="token punctuation">;</span> <span class="token keyword keyword-return">return</span> registerResponse<span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Now that our registration flow is complete, we need to create a login API for the login flow.
Login API will have one extra step, which will be to create a claim after the user is authenticated.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">HttpPost</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"Login"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">ProducesResponseType</span><span class="token attribute-arguments"><span class="token punctuation">(</span>StatusCodes<span class="token punctuation">.</span>Status200OK<span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token keyword keyword-public">public</span> <span class="token keyword keyword-async">async</span> <span class="token return-type class-name">Task<span class="token punctuation"><</span>ActionResult<span class="token punctuation">></span></span> <span class="token function">Login</span><span class="token punctuation">(</span><span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">FromBody</span></span><span class="token punctuation">]</span> <span class="token class-name">LoginCommandRequest</span> command<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword keyword-try">try</span> <span class="token punctuation">{</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> result <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> _mediator<span class="token punctuation">.</span><span class="token function">Send</span><span class="token punctuation">(</span>command<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> token <span class="token operator">=</span> <span class="token function">GetToken</span><span class="token punctuation">(</span>result<span class="token punctuation">.</span>authClaims<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword keyword-return">return</span> <span class="token function">Ok</span><span class="token punctuation">(</span><span class="token keyword keyword-new">new</span> <span class="token punctuation">{</span> token <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">JwtSecurityTokenHandler</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">WriteToken</span><span class="token punctuation">(</span>token<span class="token punctuation">)</span><span class="token punctuation">,</span> expiration <span class="token operator">=</span> token<span class="token punctuation">.</span>ValidTo <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-catch">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> ex<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token keyword keyword-return">return</span> <span class="token function">Unauthorized</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token punctuation">}</span> <span class="token keyword keyword-private">private</span> <span class="token return-type class-name">JwtSecurityToken</span> <span class="token function">GetToken</span><span class="token punctuation">(</span><span class="token class-name">List<span class="token punctuation"><</span>Claim<span class="token punctuation">></span></span> authClaims<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> authSigningKey <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">SymmetricSecurityKey</span><span class="token punctuation">(</span>Encoding<span class="token punctuation">.</span>UTF8<span class="token punctuation">.</span><span class="token function">GetBytes</span><span class="token punctuation">(</span>_configuration<span class="token punctuation">[</span><span class="token string">"JWT:Secret"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> token <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">JwtSecurityToken</span><span class="token punctuation">(</span> <span class="token named-parameter punctuation">issuer</span><span class="token punctuation">:</span> _configuration<span class="token punctuation">[</span><span class="token string">"JWT:ValidIssuer"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token named-parameter punctuation">audience</span><span class="token punctuation">:</span> _configuration<span class="token punctuation">[</span><span class="token string">"JWT:ValidAudience"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> <span class="token named-parameter punctuation">expires</span><span class="token punctuation">:</span> DateTime<span class="token punctuation">.</span>Now<span class="token punctuation">.</span><span class="token function">AddHours</span><span class="token punctuation">(</span><span class="token number">3</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token named-parameter punctuation">claims</span><span class="token punctuation">:</span> authClaims<span class="token punctuation">,</span> <span class="token named-parameter punctuation">signingCredentials</span><span class="token punctuation">:</span> <span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">SigningCredentials</span><span class="token punctuation">(</span>authSigningKey<span class="token punctuation">,</span> SecurityAlgorithms<span class="token punctuation">.</span>HmacSha256<span class="token punctuation">)</span> <span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword keyword-return">return</span> token<span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Now we will use Identity User Manager and Role Manager to authenticate the user if he is a valid user of the system and will create it claim according to his role.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | <span class="token keyword keyword-private">private</span> <span class="token keyword keyword-readonly">readonly</span> <span class="token class-name">UserManager<span class="token punctuation"><</span>IdentityUser<span class="token punctuation">></span></span> _userManager<span class="token punctuation">;</span> <span class="token keyword keyword-private">private</span> <span class="token keyword keyword-readonly">readonly</span> <span class="token class-name">RoleManager<span class="token punctuation"><</span>IdentityRole<span class="token punctuation">></span></span> _roleManager<span class="token punctuation">;</span> <span class="token keyword keyword-public">public</span> <span class="token function">LoginCommandHandler</span><span class="token punctuation">(</span><span class="token class-name">UserManager<span class="token punctuation"><</span>IdentityUser<span class="token punctuation">></span></span> userManager<span class="token punctuation">,</span> <span class="token class-name">RoleManager<span class="token punctuation"><</span>IdentityRole<span class="token punctuation">></span></span> roleManager<span class="token punctuation">)</span> <span class="token punctuation">{</span> _userManager <span class="token operator">=</span> userManager<span class="token punctuation">;</span> _roleManager <span class="token operator">=</span> roleManager<span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-public">public</span> <span class="token keyword keyword-async">async</span> <span class="token return-type class-name">Task<span class="token punctuation"><</span>LoginCommandResponse<span class="token punctuation">></span></span> <span class="token function">Handle</span><span class="token punctuation">(</span><span class="token class-name">LoginCommandRequest</span> request<span class="token punctuation">,</span> <span class="token class-name">CancellationToken</span> cancellationToken<span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> user <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> _userManager<span class="token punctuation">.</span><span class="token function">FindByEmailAsync</span><span class="token punctuation">(</span>request<span class="token punctuation">.</span>Email<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword keyword-if">if</span> <span class="token punctuation">(</span>user <span class="token operator">!=</span> <span class="token keyword keyword-null">null</span> <span class="token operator">&&</span> <span class="token keyword keyword-await">await</span> _userManager<span class="token punctuation">.</span><span class="token function">CheckPasswordAsync</span><span class="token punctuation">(</span>user<span class="token punctuation">,</span> request<span class="token punctuation">.</span>Password<span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> userRoles <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> _userManager<span class="token punctuation">.</span><span class="token function">GetRolesAsync</span><span class="token punctuation">(</span>user<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> authClaims <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">List<span class="token punctuation"><</span>Claim<span class="token punctuation">></span></span> <span class="token punctuation">{</span> <span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">Claim</span><span class="token punctuation">(</span>ClaimTypes<span class="token punctuation">.</span>Name<span class="token punctuation">,</span> user<span class="token punctuation">.</span>UserName<span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">Claim</span><span class="token punctuation">(</span>JwtRegisteredClaimNames<span class="token punctuation">.</span>Jti<span class="token punctuation">,</span> Guid<span class="token punctuation">.</span><span class="token function">NewGuid</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">ToString</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">,</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token keyword keyword-foreach">foreach</span> <span class="token punctuation">(</span><span class="token class-name"><span class="token keyword keyword-var">var</span></span> userRole <span class="token keyword keyword-in">in</span> userRoles<span class="token punctuation">)</span> <span class="token punctuation">{</span> authClaims<span class="token punctuation">.</span><span class="token function">Add</span><span class="token punctuation">(</span><span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">Claim</span><span class="token punctuation">(</span>ClaimTypes<span class="token punctuation">.</span>Role<span class="token punctuation">,</span> userRole<span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-return">return</span> <span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">LoginCommandResponse</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>authClaims <span class="token operator">=</span> authClaims<span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> <span class="token keyword keyword-throw">throw</span> <span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">Exception</span><span class="token punctuation">(</span><span class="token string">"User Email or Password is Incorrect"</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
Now after the successful login of the user, we are returning the Bearer token, which will be used to authenticate and authorize the user if he has access to the following api.
Now create a test API to check if the authentication and Authorization are working.
1 2 3 4 5 6 7 8 9 10 | <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">Authorize</span><span class="token attribute-arguments"><span class="token punctuation">(</span>Roles <span class="token operator">=</span> UserRoles<span class="token punctuation">.</span>Admin<span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">HttpGet</span><span class="token attribute-arguments"><span class="token punctuation">(</span><span class="token string">"GetUserList"</span><span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token punctuation">[</span><span class="token attribute"><span class="token class-name">ProducesResponseType</span><span class="token attribute-arguments"><span class="token punctuation">(</span>StatusCodes<span class="token punctuation">.</span>Status200OK<span class="token punctuation">)</span></span></span><span class="token punctuation">]</span> <span class="token keyword keyword-public">public</span> <span class="token keyword keyword-async">async</span> <span class="token return-type class-name">Task<span class="token punctuation"><</span>ActionResult<span class="token punctuation">></span></span> <span class="token function">Get</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token class-name"><span class="token keyword keyword-var">var</span></span> result <span class="token operator">=</span> <span class="token keyword keyword-await">await</span> _mediator<span class="token punctuation">.</span><span class="token function">Send</span><span class="token punctuation">(</span><span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">GetUsersRequest</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token keyword keyword-return">return</span> <span class="token function">Ok</span><span class="token punctuation">(</span>result<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span> |
The authorization tag will secure the application.
Now we need to add authentication and authorization configuration in our program.cs file, and we are good to go.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | builder<span class="token punctuation">.</span>Services<span class="token punctuation">.</span><span class="token function">AddAuthentication</span><span class="token punctuation">(</span>options <span class="token operator">=></span> <span class="token punctuation">{</span> options<span class="token punctuation">.</span>DefaultAuthenticateScheme <span class="token operator">=</span> JwtBearerDefaults<span class="token punctuation">.</span>AuthenticationScheme<span class="token punctuation">;</span> options<span class="token punctuation">.</span>DefaultChallengeScheme <span class="token operator">=</span> JwtBearerDefaults<span class="token punctuation">.</span>AuthenticationScheme<span class="token punctuation">;</span> options<span class="token punctuation">.</span>DefaultScheme <span class="token operator">=</span> JwtBearerDefaults<span class="token punctuation">.</span>AuthenticationScheme<span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span> <span class="token comment">// Adding Jwt Bearer</span> <span class="token punctuation">.</span><span class="token function">AddJwtBearer</span><span class="token punctuation">(</span>options <span class="token operator">=></span> <span class="token punctuation">{</span> options<span class="token punctuation">.</span>SaveToken <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">;</span> options<span class="token punctuation">.</span>RequireHttpsMetadata <span class="token operator">=</span> <span class="token boolean">false</span><span class="token punctuation">;</span> options<span class="token punctuation">.</span>TokenValidationParameters <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">TokenValidationParameters</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> ValidateIssuer <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">,</span> ValidateAudience <span class="token operator">=</span> <span class="token boolean">true</span><span class="token punctuation">,</span> ValidAudience <span class="token operator">=</span> configuration<span class="token punctuation">[</span><span class="token string">"JWT:ValidAudience"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> ValidIssuer <span class="token operator">=</span> configuration<span class="token punctuation">[</span><span class="token string">"JWT:ValidIssuer"</span><span class="token punctuation">]</span><span class="token punctuation">,</span> IssuerSigningKey <span class="token operator">=</span> <span class="token keyword keyword-new">new</span> <span class="token constructor-invocation class-name">SymmetricSecurityKey</span><span class="token punctuation">(</span>Encoding<span class="token punctuation">.</span>UTF8<span class="token punctuation">.</span><span class="token function">GetBytes</span><span class="token punctuation">(</span>configuration<span class="token punctuation">[</span><span class="token string">"JWT:Secret"</span><span class="token punctuation">]</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">}</span><span class="token punctuation">;</span> <span class="token punctuation">}</span><span class="token punctuation">)</span><span class="token punctuation">; </span> |
ASP.NET Hosting Recommendation
ASP.NET is a powerful platform for creating web applications and services. You must be comfortable with JavaScript, HTML, CSS, and C# before developing a web application in ASP.NET. On the market, there are thousands of web hosting companies providing ASP.NET Hosting. But, only very few web hosting companies could provide high quality ASP.NET hosting solution.
ASP.NET is the best development language in Windows platform, which is released by Microsoft and widely used to build all types of dynamic Web sites and XML Web services. With this article, we’re going to help you to find the best ASP.NET Hosting solution in Europe based on reliability, features, price, performance and technical support. After we reviewed about 30+ ASP.NET hosting providers in Europe, our Best ASP.NET Hosting Award in Europe goes to HostForLIFE.eu, one of the fastest growing private companies and one of the most reliable hosting providers in Europe.
1 |