My goal is to authorize users only if the current logged on user's customerId matches the customerId on the url/controller.
I'm using ASP.NET Core 2.0 with entity framework. I have extended ApplicationUser with a CustomerId int that has a FK to a CustomerIdentity table.
I am able to retrieve the customerId from the logged in user, using this method here: http://rion.io/2016/01/04/accessing-identity-info-using-dependency-injection-in-net-5/
I have made a routing:
routes.MapRoute(
name: "customers",
template: "{customerId?}/{controller=Home}/{action=Index}/{id?}");
And then in my controllers I have a customerId parameter.
Global admins have the rights to use any customerId they like, but for everyone else they can only use their customerId belonging to their logged in user.
I was thinking of using this approach to check if customerId from url, e.g. /23/Computers/Approve matches currentCustomerId
But I'm not sure how to adapt it to a policy and claim that asp.net core uses.
What I have sofar:
public class CustomerRequirement : IAuthorizationRequirement
{
public bool IsMatchingLoggedInUser { get; private set; }
public CustomerRequirement(bool isMatchingLoggedInUser)
{
IsMatchingLoggedInUser = IsMatchingLoggedInUser;
}
}
Not sure how to make this one:
public class CustomerRequirementHandler : AuthorizationHandler<CustomerRequirement>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, CustomerRequirement requirement)
{
//GetDate.CurrentCustomerId is a static int property set after user has logged in
if (GetData.CurrentCustomerId == /*Get httpContext customerId ??? "")*/ 42)
{
context.Succeed(requirement);
}
return Task.CompletedTask;
}
}
Not sure if I'm totally off here or it can be done differently? I am open for suggestions.
Update (what I ended up with)
public class ValidateCustomerAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext context)
{
if (GetData.CurrentCustomerId != (int)context.ActionArguments["customerId"])
{
context.Result = new UnauthorizedResult();
}
}
}
Then on my controllers I decorated it with this attribute. I still need to exclude admins in this, but that will come later. (and some more errorhandling :))