简体   繁体   中英

JWT “self” authentication in Net Core 2.2 MVC WebApi

I want to improve my API's security with some sort of "self" policy to validate the call to some user actions (like DELETE user) is made by the same user the token was issued to. Is there a way to do this in a similar way to the policy based authorization ?

I have a .Net Core 2.2 with MVC WebAPI running on Kestrel. I have users, roles and user-roles and I have token-based authentication with roles enabled. I can issue tokens and validate then with the "Authorize" attribute in the controllers. However, I've been looking for a way to validate that some actions to users are made only by the users itself, a "self" authentication policy to validate that, for example, user 3 is trying to delete user 3 and only user 3. I've dug up to the claims and everything and I know I can make a simple service passing the claims and the validating it but I wanted to do it in a smoother way similar to the policy-based or role-based authentication. I don't know if I can make it with some sort of middleware or something but it would be great to be able to make it as clean as possible.

[Edit]

The main purpose is to avoid users to delete resources created by other users and make them be able only to delete resources created by themselves.

[Edit2 - Solution] Thanks to Paul Lorica's Answer I can now describe how I did it.

The first thing is to create a Requirement and a Handler similar to the examples provided by Microsoft in the docs. What we do is to add a Claim to the token generation method/service we have and add the ID as NameIdentifier. After that, we inject in the IHttpContextAccessor in the handler. And then we can validate if the ID in the request is the same than the Id in the Claim. So it was very easy.

I'm adding examples of logic to make it work.

PS: Inject IHttpContextAccessor as a singleton in the startup clas or it won't work.

Handler:

public class SelfUserHandler: AuthorizationHandler<SelfUserRequirement>
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
        public SelfUserHandler(IHttpContextAccessor httpContextAccessor)
        {
            _httpContextAccessor = httpContextAccessor;
        }

        protected override Task HandleRequirementAsync(AuthorizationHandlerContext context,
                                                       SelfUserRequirement requirement)
        {
            if (!context.User.HasClaim(c => c.Type == ClaimTypes.NameIdentifier))
            {
                return Task.CompletedTask;
            }

            var nameIdentifier = context.User.FindFirst(c => c.Type == ClaimTypes.NameIdentifier).Value;

            if (_httpContextAccessor.HttpContext.Request.Path.ToString().ToUpper().Contains(nameIdentifier.ToUpper()))
            {
                context.Succeed(requirement);
            }
            else
            {
                context.Fail();
            }



            return Task.CompletedTask;
        }
    }

Requirement

public class SelfUserRequirement : IAuthorizationRequirement
    {
        public SelfUserRequirement() { }
    }

Additional info: Nate Barbettini Answer here Joe Audette Answer here

First off, when your code validates against the policy, the policy has no understanding, and does not need to know, what you are doing.

I suppose you can retrieve the context via URL. So say if its a DELETE user/3

then you can create a policy that would check the user's claims that it has an ID == 3.

See the docs here on creating policies and accessing the httpContext

https://docs.microsoft.com/en-us/aspnet/core/security/authorization/policies?view=aspnetcore-2.2

Its a bit of a naive check, I would rather just place that logic within the method of the controller.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM