With JSON Web Tokens: Sarathlal Saseendran
With JSON Web Tokens: Sarathlal Saseendran
Login Post
Ask Question
TECHNOLOGIES ANSWERS LEARN NEWS BLOGS VIDEOS INTERVIEW PREP BOOKS EVENTS CAREER MEMBERS JOBS C# Corner Search
Sarathlal Saseendran Updated date Sep 19, 2020 Exploring Subject <T> In Reactive Extensions For
.Net
456.3k
40
61 Micro Frontends With Webpack
What’s New In iPhone 13
Understanding Synchronization Context
Task.ConfigureAwait In Action
Download Free .NET & JAVA Office Files API Try Free File Format APIs for Word/Excel/PDF View All
JWTAuthentication.zip
TRENDING UP
Introduction The Best VS Code Extensions For Remote
Authentication is the process of validating user credentials and authorization is the process of checking 01 Working
privileges for a user to access specific modules in an application. In this article, we will see how to protect an
ASP.NET Core Web API application by implementing JWT authentication. We will also see how to use 02 Getting Started With .NET 6.0
authorization in ASP.NET Core to provide access to various functionality of the application. We will store user
credentials in an SQL server database and we will use Entity framework and Identity framework for database 03 How To Post Data In ASP.NET Core Using Ajax
operations.
04 Visual Studio 2022 Installation Step By Step
JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for 05 New Features In Blazor With .NET 6
securely transmitting information between parties as a JSON object. This information can be verified and
Debugging The Hottest Release Of Visual Studio
trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a 06 With Code Demos
public/private key pair using RSA or ECDSA.
Implementing Smart Contract in ASP.NET
In its compact form, JSON Web Tokens consist of three parts separated by dots (.), which are: 07 Application
The Best VS Code Extensions To Supercharge
Header 08 Git
Payload
Signature 09 Getting Started With ASP.NET Core 6.0
Therefore, a JWT typically looks like the following. 10 7 Minutes to better Selling Podcast Ep. 9
View All
xxxx.yyyy.zzzz
Please refer to below link for more details about JSON Web Tokens.
https://jwt.io/introduction/
We have added two constant values “Admin” and “User” as roles. You can add many roles as you wish.
Create class “RegisterModel” for new user registration.
RegisterModel.cs
01. using System.ComponentModel.DataAnnotations;
02.
03. namespace JWTAuthentication.Authentication
04. {
05. public class RegisterModel
06. {
07. [Required(ErrorMessage = "User Name is required")]
08. public string Username { get; set; }
09.
10. [EmailAddress]
11. [Required(ErrorMessage = "Email is required")]
12. public string Email { get; set; }
13.
14. [Required(ErrorMessage = "Password is required")]
15. public string Password { get; set; }
16.
17. }
18. }
We can create an API controller “AuthenticateController” inside the “Controllers” folder and add below code.
AuthenticateController.cs
01. using JWTAuthentication.Authentication;
02. using Microsoft.AspNetCore.Http;
03. using Microsoft.AspNetCore.Identity;
04. using Microsoft.AspNetCore.Mvc;
05. using Microsoft.Extensions.Configuration;
06. using Microsoft.IdentityModel.Tokens;
07. using System;
08. using System.Collections.Generic;
09. using System.IdentityModel.Tokens.Jwt;
10. using System.Security.Claims;
11. using System.Text;
12. using System.Threading.Tasks;
13.
14. namespace JWTAuthentication.Controllers
15. {
16. [Route("api/[controller]")]
17. [ApiController]
18. public class AuthenticateController : ControllerBase
19. {
20. private readonly UserManager<ApplicationUser> userManager;
21. private readonly RoleManager<IdentityRole> roleManager;
22. private readonly IConfiguration _configuration;
23.
24. public AuthenticateController(UserManager<ApplicationUser> userManager,
25. {
26. this.userManager = userManager;
27. this.roleManager = roleManager;
28. _configuration = configuration;
29. }
30.
31. [HttpPost]
32. [Route("login")]
33. public async Task<IActionResult> Login([FromBody] LoginModel model)
34. {
35. var user = await userManager.FindByNameAsync(model.Username);
36. if (user != null && await userManager.CheckPasswordAsync(user, mode
37. {
38. var userRoles = await userManager.GetRolesAsync(user);
39.
40. var authClaims = new List<Claim>
41. {
42. new Claim(ClaimTypes.Name, user.UserName),
43. new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToStr
44. };
45.
46. foreach (var userRole in userRoles)
47. {
48. authClaims.Add(new Claim(ClaimTypes.Role, userRole));
49. }
50.
51. var authSigningKey = new SymmetricSecurityKey(Encoding.UTF8.Get
52.
53. var token = new JwtSecurityToken(
54. issuer: _configuration["JWT:ValidIssuer"],
55. audience: _configuration["JWT:ValidAudience"],
56. expires: DateTime.Now.AddHours(3),
57. claims: authClaims,
58. signingCredentials: new SigningCredentials(authSigningKey,
59. );
60.
61. return Ok(new
62. {
63. token = new JwtSecurityTokenHandler().WriteToken(token),
64. expiration = token.ValidTo
65. });
66. }
67. return Unauthorized();
68. }
69.
70. [HttpPost]
71. [Route("register")]
72. public async Task<IActionResult> Register([FromBody] RegisterModel mode
73. {
74. var userExists = await userManager.FindByNameAsync(model.Username);
75. if (userExists != null)
76. return StatusCode(StatusCodes.Status500InternalServerError, new
77.
78. ApplicationUser user = new ApplicationUser()
79. {
80. Email = model.Email,
81. SecurityStamp = Guid.NewGuid().ToString(),
82. UserName = model.Username
83. };
84. var result = await userManager.CreateAsync(user, model.Password);
85. if (!result.Succeeded)
86. return StatusCode(StatusCodes.Status500InternalServerError, new
87.
88. return Ok(new Response { Status = "Success", Message = "User create
89. }
90.
91. [HttpPost]
92. [Route("register-admin")]
93. public async Task<IActionResult> RegisterAdmin([FromBody] RegisterModel
94. {
95. var userExists = await userManager.FindByNameAsync(model.Username);
96. if (userExists != null)
97. return StatusCode(StatusCodes.Status500InternalServerError, new
98.
99. ApplicationUser user = new ApplicationUser()
100. {
101. Email = model.Email,
102. SecurityStamp = Guid.NewGuid().ToString(),
103. UserName = model.Username
104. };
105. var result = await userManager.CreateAsync(user, model.Password);
106. if (!result.Succeeded)
107. return StatusCode(StatusCodes.Status500InternalServerError, new
108.
109. if (!await roleManager.RoleExistsAsync(UserRoles.Admin))
110. await roleManager.CreateAsync(new IdentityRole(UserRoles.Admin)
111. if (!await roleManager.RoleExistsAsync(UserRoles.User))
112. await roleManager.CreateAsync(new IdentityRole(UserRoles.User))
113.
114. if (await roleManager.RoleExistsAsync(UserRoles.Admin))
115. {
116. await userManager.AddToRoleAsync(user, UserRoles.Admin);
117. }
118.
119. return Ok(new Response { Status = "Success", Message = "User create
120. }
121. }
122. }
We have added three methods “login”, “register”, and “register-admin” inside the controller class. Register
and register-admin are almost same but the register-admin method will be used to create a user with admin
role. In login method, we have returned a JWT token after successful login.
We can make below changes in “ConfigureServices” and “Configure” methods in “Startup” class as well.
Startup.cs
01. using JWTAuthentication.Authentication;
02. using Microsoft.AspNetCore.Authentication.JwtBearer;
03. using Microsoft.AspNetCore.Builder;
04. using Microsoft.AspNetCore.Hosting;
05. using Microsoft.AspNetCore.Identity;
06. using Microsoft.EntityFrameworkCore;
07. using Microsoft.Extensions.Configuration;
08. using Microsoft.Extensions.DependencyInjection;
09. using Microsoft.Extensions.Hosting;
10. using Microsoft.IdentityModel.Tokens;
11. using System.Text;
12.
13. namespace JWTAuthentication
14. {
15. public class Startup
16. {
17. public Startup(IConfiguration configuration)
18. {
19. Configuration = configuration;
20. }
21.
22. public IConfiguration Configuration { get; }
23.
24. // This method gets called by the runtime. Use this method to add servi
25. public void ConfigureServices(IServiceCollection services)
26. {
27. services.AddControllers();
28.
29. // For Entity Framework
30. services.AddDbContext<ApplicationDbContext>
(options => options.UseSqlServer(Configuration.GetConnectionString("ConnStr")))
31.
32. // For Identity
33. services.AddIdentity<ApplicationUser, IdentityRole>()
34. .AddEntityFrameworkStores<ApplicationDbContext>()
35. .AddDefaultTokenProviders();
36.
37. // Adding Authentication
38. services.AddAuthentication(options =>
39. {
40. options.DefaultAuthenticateScheme = JwtBearerDefaults.Authentic
41. options.DefaultChallengeScheme = JwtBearerDefaults.Authenticati
42. options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
43. })
44.
45. // Adding Jwt Bearer
46. .AddJwtBearer(options =>
47. {
48. options.SaveToken = true;
49. options.RequireHttpsMetadata = false;
50. options.TokenValidationParameters = new TokenValidationParamete
51. {
52. ValidateIssuer = true,
53. ValidateAudience = true,
54. ValidAudience = Configuration["JWT:ValidAudience"],
55. ValidIssuer = Configuration["JWT:ValidIssuer"],
56. IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.G
57. };
58. });
59. }
60.
61. // This method gets called by the runtime. Use this method to configure
62. public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
63. {
64. if (env.IsDevelopment())
65. {
66. app.UseDeveloperExceptionPage();
67. }
68.
69. app.UseRouting();
70.
71. app.UseAuthentication();
72. app.UseAuthorization();
73.
74. app.UseEndpoints(endpoints =>
75. {
76. endpoints.MapControllers();
77. });
78. }
79. }
80. }
We must create a database and required tables before running the application. As we are using entity
framework, we can use below database migration command with package manger console to create a
migration script.
“add-migration Initial”
Use below command to create database and tables.
“update-database”
If you check the database using SQL server object explorer, you can see that below tables are created inside
the database.
Above seven tables are used by identity framework to manage authentication and authorization.
We can run the application and try to access get method in weatherforecast controller from Postman tool.
We have received a 401 unauthorized error. Because, we have added Authorize attribute to entire controller.
We must provide a valid token via request header to access this controller and methods inside the
controller.
We can create a new user using register method in authenticate controller.
We can use above user credentials to login and get a valid JWT token.
We have received a token after successful login with above credentials.
We can pass above token value as a bearer token inside the authorization tab and call get method of
weatherforecast controller again.
This time, we have successfully received the values from controller.
We can modify the weatherforecast controller with role-based authorization.
Now, only users with admin role can access this controller and methods.
We can try to access the weatherforecast controller with same token again in Postman tool.
We have received a 403 forbidden error now. Even though, we are passing a valid token we don’t have
sufficient privilege to access the controller. To access this controller, user must have an admin role
permission. Current user is a normal user and do not have any admin role permission.
We can create a new user with admin role. We already have a method “register-admin” in authenticate
controller for the same purpose.
We can login with this new user credentials and get a new token and use this token instead of old token to
access the weatherforecast controller.
We have again received the values from weatherforecast controller successfully.
We can see the token payload and other details using jwt.io site.
Inside the payload section, you can see the user name, role and other details as claims.
Conclusion
In this post, we have seen how to create a JSON web token in ASP.NET Core Web API application and use this
token for authentication and authorization. We have created two users, one without any role and one with
admin role. We have applied the authentication and authorization in controller level and saw the different
behaviors with these two users.
ASP.NET Core Web API Authentication in ASP.NET Core Authorization in ASP.NET Core Json Web Tokens
OUR BOOKS
Sarathlal Saseendran
115 5.6m 3
A passionate human being loves to learn new things always.
https://www.linkedin.com/in/sarathlal-saseendran/
61
40 View Previous Comments
Type your comment here and press Enter Key (Minimum 10 characters)
Sir please make a blog on facebook n google authentication in same above application
ishwar giri Sep 08, 2021
1380 708 0 0 0 Reply
Good Article......
Amit Gautam Aug 21, 2021
1888 187 0 0 0 Reply
It is a very good and clear article. To help other with some tips, in IIS you must open the port 61955 in web site's
bindings in order to do calls with postman. Moreover, if someone apply that instuction in his applicatation then
in order to create successfully the authentication tables the (-context ApplicationDbContext) must be used in
both Package manager Console commands. e.g. (add-migration Initial -Context ApplicationDbContext) and
(update-database -Context ApplicationDbContext). I hope it help someone from losing time!
Κωνσταντίνος Μαλλιαρίδης Jul 15, 2021
2067 8 0 1 0 Reply
Nice Article
Mayank Mishra May 03, 2021
1978 97 0 0 0 Reply
About Us
Contact Us
Privacy Policy
Terms
Media Kit
Sitemap
Report a Bug
FAQ
Partners
C# Tutorials
Common Interview Questions
Stories
Consultants
Ideas
Certifications
©2021 C# Corner. All contents are copyright of their authors.