Implementing custom policies in ASP.NET Core using the HttpContext

This article shows how to implement a custom ASP.NET Core policy using the AuthorizationHandler class. The handler validates, that the identity from the HttpContext has the authorization to update the object in the database.

Code: https://github.com/damienbod/AspNetCoreAngularSignalRSecurity

History

2023-01-08 Updated Angular 15, .NET 7
2021-01-25 Updated Angular 11.1.0 .NET 5, ngrx implementation
2020-03-21 updated packages, fixed Admin UI STS
2019-08-18 Updated ASP.NET Core 3.0, Angular 8.2.2
2019-02-06 Updated Angular 7.2.4, latest NGRX, SignalR CORS fix
2018-12-12 Updated .NET Core 2.2, ASP.NET Core SignalR 1.1.0, Angular 7.1.3
2018-05-31 Updated Microsoft.AspNetCore.SignalR 2.1
2018-05-08 Updated Microsoft.AspNetCore.SignalR 2.1 rc1, Angular 6
2018-03-15 Updated signalr Microsoft.AspNetCore.SignalR 1.0.0-preview1-final, Angular 5.2.8, @aspnet/signalr 1.0.0-preview1-update1

Scenerio

In the example, each admin user of the client application, can create DataEventRecord entities which can only be accessed by the corresponding identity. If a different identity with a different user sends a PUT request to update the object, a 401 response is returned. Because the Username from the identity is saved in the database for each entity, the custom policy can validate the identity and the entity to be updated.

Creating the Requirement for the Policy

A simple requirement is created for the policy implementation. The AuthorizationHandler implementation requires this and the requirement class is also used to add the policy to the application.

using Microsoft.AspNetCore.Authorization; 

namespace ApiServer.Policies;

public class CorrectUserRequirement : IAuthorizationRequirement{}

Creating the custom Handler for the Policy

If a method is called, which is protected by the CorrectUserHandler, the HandleRequirementAsync is executed. In this method, the id of the object to be updated is extracted from the url path. The id is then used to select the Username from the database, which is then compared to the Username from the HttpContext identity name. If the values are not equal, no success message is returned.

using ApiServer.Repositories; 
using Microsoft.AspNetCore.Authorization; 
using System; 
using System.Threading.Tasks; 

namespace ApiServer.Policies;

public class CorrectUserHandler : AuthorizationHandler<CorrectUserRequirement>
{ 
	private readonly IDataEventRecordRepository _dataEventRecordRepository; 
	
	public CorrectUserHandler(IDataEventRecordRepository dataEventRecordRepository) 
	{
		_dataEventRecordRepository = dataEventRecordRepository; 
	} 
	
	protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CorrectUserRequirement requirement) 
	{ 
		if (context == null) throw new ArgumentNullException(nameof(context)); 
		
		if (requirement == null) throw new ArgumentNullException(nameof(requirement)); 
		
		var authFilterCtx = (Microsoft.AspNetCore.Mvc.Filters.AuthorizationFilterContext)context.Resource; 
		var httpContext = authFilterCtx.HttpContext; var pathData = httpContext.Request.Path.Value.Split("/"); 
		
		long id = long.Parse(pathData[pathData.Length -1]); 
		var username = _dataEventRecordRepository.GetUsername(id); 
		
		if (username == httpContext.User.Identity.Name) 
		{ 	
			context.Succeed(requirement); 
		} 
		
		return Task.CompletedTask; 
	}
}

Adding the policy to the application

The custom policy is added to the ASP.NET Core application using the AddAuthorization extension using the requirement.

builder.Services.AddAuthorization( options => 
{ 
     // ... 
     options.AddPolicy("correctUser",

     policyCorrectUser => { policyCorrectUser.Requirements.Add(new CorrectUserRequirement());  }); 
});

Using the policy in the ASP.NET Core controller

The PUT method uses the correctUser policy to authorize the request.

[Authorize("dataEventRecordsAdmin")] 
[Authorize("correctUser")] 
[HttpPut("{id}")] 
public IActionResult Put(long id, [FromBody]DataEventRecordDto dataEventRecordDto) 
{ 
	_dataEventRecordRepository.Put(id, dataEventRecordDto); 
	
	return NoContent(); 
}

If a user logs in, and tries to update an entity belonging to a different user, the request is rejected.

If a user logs in, and tries to update an entity belonging to a different user, the request is rejected.

Links:

https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies

9 comments

  1. […] Implementing custom policies in ASP.NET Core using the HttpContext – Damien Bowden […]

  2. […] Implementing custom policies in ASP.NET Core using the HttpContext (Damien Bowden) […]

  3. […] L’implémentation de Custom Policies dans ASP.NET Core en utilisant HttpContext. […]

    1. Hi Cristovao

      This is for ASP.NET Core 2.0

      Greetings Damien

  4. Thanks for posting this. I just went through it and wanted to point out that you are missing this line in the Startup class:

    services.AddSingleton();

    Also, you duplicated a line in your CorrectUserRequirement class.

    1. Woops. IAuthorizationHandler, CorrectUserHandler should be in that AddSingleton.

      services.AddSingleton < IAuthorizationHandler, CorrectUserHandler > ();

    2. thanks, will fix it
      greetings Damien

  5. As said Wei,
    It does not work until you would add:

    services.AddSingleton ();

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: