Section 5 of 6
Resource-Based Authorization
🎯 What You'll Learn
- What is resource-based authorization
- IAuthorizationService
- AuthorizeAsync()
- Creating resource handlers
- InvenTrack example
What is Resource-Based Authorization?
Resource-based authorization makes decisions based on the specific resource being accessed. For example, users can only edit their own products.
💡 Use Case
Use resource-based authorization when the authorization decision depends on the resource data itself, not just the user's role or claims.
IAuthorizationService
Inject IAuthorizationService to perform authorization checks in code.
Basic Usage
C#
public class ProductsController : Controller
{
private readonly IAuthorizationService _authorizationService;
public ProductsController(IAuthorizationService authorizationService)
{
_authorizationService = authorizationService;
}
public async Task<IActionResult> Edit(int id)
{
var product = await _context.Products.FindAsync(id);
var authResult = await _authorizationService.AuthorizeAsync(
User, product, "CanEditProduct");
if (!authResult.Succeeded)
return Forbid();
return View(product);
}
}
Creating Resource Handler
1. Define Requirement
ProductOwnerRequirement.cs
C#
public class ProductOwnerRequirement : IAuthorizationRequirement
{
}
2. Create Handler
ProductOwnerHandler.cs
C#
public class ProductOwnerHandler
: AuthorizationHandler<ProductOwnerRequirement, Product>
{
protected override Task HandleRequirementAsync(
AuthorizationHandlerContext context,
ProductOwnerRequirement requirement,
Product resource)
{
var userId = context.User.FindFirst(ClaimTypes.NameIdentifier)?.Value;
if (resource.CreatedBy == userId)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
3. Register Handler and Policy
Program.cs
C#
builder.Services.AddSingleton<IAuthorizationHandler, ProductOwnerHandler>();
builder.Services.AddAuthorization(options =>
{
options.AddPolicy("CanEditProduct", policy =>
policy.Requirements.Add(new ProductOwnerRequirement()));
});
Complete InvenTrack Example
Product Model
C#
public class Product
{
public int Id { get; set; }
public string Name { get; set; } = string.Empty;
public string CreatedBy { get; set; } = string.Empty;
}
ProductsController.cs
C#
[Authorize]
public class ProductsController : Controller
{
private readonly IAuthorizationService _authorizationService;
[HttpGet]
public async Task<IActionResult> Edit(int id)
{
var product = await _context.Products.FindAsync(id);
if (product == null)
return NotFound();
// Check if user can edit this specific product
var authResult = await _authorizationService
.AuthorizeAsync(User, product, "CanEditProduct");
if (!authResult.Succeeded)
return Forbid();
return View(product);
}
}
Key Takeaways
- Resource-based: Authorization depends on resource data
- IAuthorizationService: Perform checks in code
- AuthorizeAsync(): Check authorization for resource
- IAuthorizationRequirement: Define requirement
- AuthorizationHandler: Implement authorization logic
- Use case: Users can only edit their own data