Learning Objectives
- Learn how to implement token-based authentication using JWT (JSON Web Tokens) in ASP.NET Core.
- Understand how to use role-based and policy-based authorization to secure API endpoints.
- Learn about ASP.NET Core Identity, and how to customize it or implement a custom authentication solution if needed.
1. Authentication with JWT
What is JWT? JWT (JSON Web Token) is a compact, URL-safe token format used to securely transmit information between parties. In the context of APIs, JWTs are commonly used for authentication by creating a token that users receive after successfully logging in. They include user information (claims) and are signed for security.
How JWT Authentication Works:
- The user logs in with a username and password.
- If valid, the server creates a JWT token, which includes user claims.
- The client uses this token to make authenticated requests to the API by including it in the Authorization header.
Example: Setting Up JWT Authentication in ASP.NET Core:
Add Packages:
Use the NuGet Package Manager to install Microsoft.AspNetCore.Authentication.JwtBearer
.
Configure JWT in Program.cs
:
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"]))
};
});
Generating JWT Tokens in a Service:
public string GenerateToken(User user)
{
var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_configuration["Jwt:Key"]));
var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);
var claims = new[]
{
new Claim(ClaimTypes.Name, user.Username),
new Claim(ClaimTypes.Role, user.Role)
};
var token = new JwtSecurityToken(_configuration["Jwt:Issuer"],
_configuration["Jwt:Audience"],
claims,
expires: DateTime.Now.AddMinutes(30),
signingCredentials: credentials);
return new JwtSecurityTokenHandler().WriteToken(token);
}
This method generates a JWT token that contains user information such as the username and role.
Real-Life Example: In an e-commerce system, JWTs can be used to authenticate customers before they access their order details or payment information.
2. Authorization
Role-Based Authorization: Role-based authorization allows you to control access to resources based on user roles. For example, users can have roles like Admin, User, or Manager.
Example: Role-Based Authorization in Controller:
[Authorize(Roles = "Admin")]
[HttpPost("create-product")]
public IActionResult CreateProduct([FromBody] Product product)
{
// Only admins can add products
return Ok("Product created successfully.");
}
- Explanation: Only users with the Admin role can access this endpoint.
Policy-Based Authorization: Policy-based authorization allows more complex requirements than role-based authorization. Policies can include multiple conditions, such as requiring both a specific role and age.
Example: Defining a Policy
Configure Policies in Program.cs
:
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("AdminOnly", policy =>
policy.RequireRole("Admin"));
options.AddPolicy("AgeRequirement", policy =>
policy.RequireClaim(ClaimTypes.DateOfBirth));
});
Using a Policy in a Controller:
[Authorize(Policy = "AdminOnly")]
[HttpDelete("delete-product/{id}")]
public IActionResult DeleteProduct(int id)
{
// Only admins can delete products
return Ok("Product deleted successfully.");
}
Real-Life Example: In a user management system, different endpoints can be restricted based on user roles or specific claims. For example, only Admin users can delete accounts.
3. ASP.NET Core Identity
What is ASP.NET Core Identity? ASP.NET Core Identity is a membership system that provides login functionality for applications. It includes features such as user management, password hashing, and roles.
You can either use the default Identity system or create a custom authentication solution.
Setting Up ASP.NET Core Identity:
Add ASP.NET Core Identity in Program.cs
:
builder.Services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
Customize User Entity: You can customize the user entity by inheriting from IdentityUser
:
public class ApplicationUser : IdentityUser
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
Custom Authentication Solution: In some cases, you may want to create a custom authentication solution using JWT tokens or another approach instead of ASP.NET Core Identity.
Real-Life Example: In a financial application, Identity can help manage users and assign roles such as Accountant, Manager, and Customer.
Examples
Simple Example: Login and Generate JWT Token
User logs in and receives a JWT token.
Code Snippet:
[HttpPost("login")]
public IActionResult Login([FromBody] LoginModel login)
{
if (login.Username == "admin" && login.Password == "password")
{
var token = _authService.GenerateToken(new User { Username = "admin", Role = "Admin" });
return Ok(new { Token = token });
}
return Unauthorized();
}
Real-Life Example: Used in an e-commerce system for customer login.
Simple Example: Role-Based Authorization
Restrict an endpoint to only allow Admin users to access it.
Code Snippet:
[Authorize(Roles = "Admin")]
[HttpPost("add-user")]
public IActionResult AddUser([FromBody] User user)
{
return Ok("User added successfully.");
}
Real-Life Example: In a user management system, adding new users might be restricted to admin roles.
Simple Example: Policy-Based Authorization
Use a policy to require a specific claim.
Code Snippet:
[Authorize(Policy = "AgeRequirement")]
[HttpGet("restricted-content")]
public IActionResult GetRestrictedContent()
{
return Ok("This is restricted content.");
}
Real-Life Example: In a financial application, sensitive data can be restricted based on user age or other conditions.
Key Takeaways
- JWT Authentication is used for securing APIs by issuing and validating tokens.
- Role-Based and Policy-Based Authorization are used to control access to different parts of your application.
- ASP.NET Core Identity provides a complete solution for managing users, roles, and authentication.
Practical Questions
- What is the difference between authentication and authorization?
- How can you implement JWT authentication to secure an API?
- When would you use policy-based authorization instead of role-based authorization?
New Concepts in .NET 8
New in .NET 8:
- Native AOT Improvements: Native AOT (Ahead of Time) can help reduce startup time for authentication-heavy applications by compiling applications directly into machine code, making APIs more responsive.
- Enhanced Security Features: .NET 8 introduces better default configurations for secure JWT token handling and improvements in token lifetimes for enhanced API security.