Round #214
07 May 2026, 14:20· csharp· meta/llama-3.3-70b-instruct· r12-real-contracts
- Complexity
- band 1
- ZP / UO / OBS
- 3 / 5 / 3
- Journey weight
- 794
- Lightshift ΔL
- —
Prompt
Implement resource-based authorization using IAuthorizationHandler
Zero-point index (what the engine surfaced)
ZPI-ZPI-0007 | 2026-05-07T14:20:48Z
Implement resource-based authorization using IAuthorizationHandler
ZERO POINT — 3 entries (structural invariants)
● hsl(178.91, 100%, 21%) IAuthorizationHandler [contract]
● hsl(14.32, 100%, 21%) IAuthorizationRequirement [contract]
● hsl(349.17, 100%, 21%) AuthorizationHandler<TRequirement> [contract]
UNOBSERVED — 5 entries (implied truths)
○ hsl(27.69, 100%, 50%) async [feature]
○ hsl(49.23, 100%, 30%) try [feature]
○ hsl(31.38, 100%, 40%) Scoped registration [function]
○ hsl(44.31, 100%, 25%) IOptions of T binding [function]
○ hsl(112.62, 100%, 16%) Token validation parameters [function]
OBSERVED — 3 entries (explicit in request)
◉ hsl(85.13, 100%, 36%) using [feature]
◉ hsl(234.87, 100%, 36%) using [feature]
◉ hsl(121.85, 100%, 10%) Resource-based authorization [function]
COMPLEXITY │ 11 entries │ spread: 207° │ band: MEDIUM
Baseline response (no ZPI)
**Resource-Based Authorization using IAuthorizationHandler**
===========================================================
In this example, we will implement resource-based authorization using `IAuthorizationHandler` in a C# application.
**Step 1: Create a Resource**
---------------------------
First, let's create a resource that we want to protect with authorization. For example, let's create a `Document` class:
```csharp
public class Document
{
public int Id { get; set; }
public string Name { get; set; }
public string OwnerId { get; set; }
}
```
**Step 2: Create an Authorization Requirement**
------------------------------------------
Next, let's create an authorization requirement that will be used to protect the `Document` resource. We will create a `DocumentOwnerRequirement` class that inherits from `IAuthorizationRequirement`:
```csharp
public class DocumentOwnerRequirement : IAuthorizationRequirement
{
public string DocumentId { get; set; }
}
```
**Step 3: Create an Authorization Handler**
-----------------------------------------
Now, let's create an authorization handler that will handle the `DocumentOwnerRequirement`. We will create a `DocumentOwnerHandler` class that inherits from `IAuthorizationHandler`:
```csharp
public class DocumentOwnerHandler : AuthorizationHandler<DocumentOwnerRequirement>
{
private readonly IUserService _userService;
private readonly IDocumentService _documentService;
public DocumentOwnerHandler(IUserService userService, IDocumentService documentService)
{
_userService = userService;
_documentService = documentService;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, DocumentOwnerRequirement requirement)
{
var userId = context.User.FindFirstValue(ClaimTypes.NameIdentifier);
var document = await _documentService.GetDocumentAsync(requirement.DocumentId);
if (document != null && document.OwnerId == userId)
{
context.Succeed(requirement);
}
}
}
```
In this example, the `DocumentOwnerHandler` checks if the current user is the owner of the document. If the user is the owner, the handler succeeds the requirement.
**Step 4: Register the Authorization Handler**
--------------------------------------------
Finally, let's register the `DocumentOwnerHandler` in the `Startup.cs` file:
```csharp
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(options =>
{
options.AddPolicy("DocumentOwnerPolicy", policy => policy.Requirements.Add(new DocumentOwnerRequirement()));
});
services.AddSingleton<IAuthorizationHandler, DocumentOwnerHandler>();
}
```
**Step 5: Use the Authorization Policy**
-----------------------------------------
Now, we can use the `DocumentOwnerPolicy` to protect the `Document` resource. For example, we can create a controller that requires the `DocumentOwnerPolicy`:
```csharp
[Authorize(Policy = "DocumentOwnerPolicy")]
public class DocumentController : Controller
{
private readonly IDocumentService _documentService;
public DocumentController(IDocumentService documentService)
{
_documentService = documentService;
}
[HttpGet]
public async Task<IActionResult> GetDocument(int id)
{
var requirement = new DocumentOwnerRequirement { DocumentId = id.ToString() };
var result = await AuthorizationService.AuthorizeAsync(User, requirement);
if (!result.Succeeded)
{
return Forbid();
}
var document = await _documentService.GetDocumentAsync(id);
return Ok(document);
}
}
```
In this example, the `DocumentController` requires the `DocumentOwnerPolicy` to access the `GetDocument` action. The `DocumentOwnerHandler` will check if the current user is the owner of the document, and if not, the action will return a 403 Forbidden response.
**Example Use Case**
--------------------
Here's an example use case:
1. Create a new document with an owner ID of "1".
2. Create a new user with an ID of "1" and a role of "Owner".
3. Log in as the user with ID "1".
4. Try to access the document with ID "1" using the `GetDocument` action.
5. The `DocumentOwnerHandler` will check if the current user is the owner of the document, and since they are, the action will return the document.
Note: This is a simplified example and you should adapt it to your specific use case. Additionally, you should ensure that the `IUserService` and `IDocumentService` interfaces are properly implemented and registered in the DI container.
Enhanced response (with ZPI)
### Resource-Based Authorization Implementation
Below is an example implementation of resource-based authorization using `IAuthorizationHandler`. This example includes a custom requirement, a custom handler, and registration in the DI container.
#### Custom Requirement
First, we define a custom requirement that will be used to specify the resource type and the operation being performed.
```csharp
public class ResourceOperationRequirement : IAuthorizationRequirement
{
public string ResourceType { get; }
public string Operation { get; }
public ResourceOperationRequirement(string resourceType, string operation)
{
ResourceType = resourceType;
Operation = operation;
}
}
```
#### Custom Handler
Next, we create a custom handler that will evaluate the custom requirement. This handler will check if the user has permission to perform the specified operation on the specified resource type.
```csharp
public class ResourceOperationHandler : AuthorizationHandler<ResourceOperationRequirement>
{
private readonly IOptions<AuthorizationSettings> _authorizationSettings;
public ResourceOperationHandler(IOptions<AuthorizationSettings> authorizationSettings)
{
_authorizationSettings = authorizationSettings;
}
protected override async Task HandleRequirementAsync(AuthorizationHandlerContext context, ResourceOperationRequirement requirement)
{
var claims = context.User.Claims;
var userId = claims.FirstOrDefault(c => c.Type == "id")?.Value;
// Check if the user has permission to perform the operation on the resource type
if (HasPermission(userId, requirement.ResourceType, requirement.Operation))
{
context.Succeed(requirement);
}
await Task.CompletedTask;
}
private bool HasPermission(string userId, string resourceType, string operation)
{
// This is a placeholder for your actual permission checking logic
// You can use a database or a cache to store the permissions
var permissions = _authorizationSettings.Value.Permissions;
return permissions.ContainsKey(userId) && permissions[userId].ContainsKey(resourceType) && permissions[userId][resourceType].Contains(operation);
}
}
public class AuthorizationSettings
{
public Dictionary<string, Dictionary<string, List<string>>> Permissions { get; set; }
}
```
#### Registration in DI Container
Finally, we register the custom handler and the custom requirement in the DI container.
```csharp
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthorization(options =>
{
options.AddPolicy("ResourceOperationPolicy", policy => policy.Requirements.Add(new ResourceOperationRequirement("ResourceType", "Operation")));
});
services.AddSingleton<IAuthorizationHandler, ResourceOperationHandler>();
services.Configure<AuthorizationSettings>(Configuration.GetSection("AuthorizationSettings"));
}
```
#### Usage
To use the custom handler, you can decorate your controllers or actions with the `[Authorize]` attribute and specify the policy name.
```csharp
[Authorize(Policy = "ResourceOperationPolicy")]
public class MyController : Controller
{
[HttpGet]
public IActionResult Get()
{
return Ok();
}
}
```
In this example, the `ResourceOperationHandler` will be triggered when the `Get` action is called, and it will check if the user has permission to perform the `Operation` on the `ResourceType`. If the user has permission, the action will be executed; otherwise, a 403 Forbidden response will be returned.
### Explanation
This implementation provides a basic example of resource-based authorization using `IAuthorizationHandler`. The custom requirement `ResourceOperationRequirement` specifies the resource type and the operation being performed, and the custom handler `ResourceOperationHandler` evaluates this requirement by checking if the user has permission to perform the operation on the resource type.
The `ResourceOperationHandler` uses the `IOptions` interface to inject the `AuthorizationSettings` instance, which contains the permissions configuration. The `HasPermission` method checks if the user has permission to perform the operation on the resource type by looking up the permissions in the `AuthorizationSettings` instance.
The custom handler is registered in the DI container as a singleton, and the custom requirement is added to the authorization policy. The `[Authorize]` attribute is used to decorate the controllers or actions that require authorization, and the policy name is specified to trigger the custom handler.
This implementation provides a flexible and extensible way to implement resource-based authorization, and it can be customized to fit the specific requirements of your application.
Grader chain
Each grader reads the same baseline + enhanced pair and casts an independent verdict. Disagreement is the framework's own signal — not noise to be averaged away.
V1claude-haiku-4-5-20251001
WorseV4qwen2.5-coder-7b-instruct
BetterComments
Our grader said what it said. What do you say? Comment as a guest below.
No comments yet. Be the first to say what you make of this round.