Resource based authorization in .net

后端 未结 5 683
故里飘歌
故里飘歌 2020-12-29 11:20

Let\'s say that you have a .net web api with a GetResource(int resourceId) action. This action (with the specified id) should only be authorized for a user associated with t

5条回答
  •  被撕碎了的回忆
    2020-12-29 11:46

    For resource based authorization, I'd suggest to use claim based identity and embed user id as a claim. Write an extension method to read the claim from identity. So the sample code will look like:

    public Resource GetResource(int id)
    {
         var resource = resourceRepository.Find(id);
        if (resource.UserId != User.Identity.GetUserId())
        {
            throw new HttpResponseException(HttpStatusCode.Unauthorized);
        }
    
        return resource;
    }
    

    If you want to simplify the code further more, you may write a UserRepository which knows user data and resource repository to centralize the code. The code will look like:

    public Resource GetResource(int id)
    {
        return User.Identity.GetUserRepository().FindResource(id);
    }
    

    For role based authorization, AuthorizeAttribute will be the best place to handle it and you'd better use separate action or controller for that.

    [Authorize(Roles = "admin")]
    public Resource GetResourceByAdmin(int id)
    {
        return resourceRepository.Find(id);
    }
    

    [Edit] If OP do want to use one single action to handle different types of users, I personally prefer to use a user repository factory. The action code will be:

    public Resource GetResource(int id)
    {
        return User.GetUserRepository().FindResource(id);
    }
    

    The extension method will be:

    public static IUserRepository GetUserRepository(this IPrincipal principal)
    {
        var resourceRepository = new ResourceRepository();
        bool isAdmin = principal.IsInRole("Admin");
        if (isAdmin)
        {
            return new AdminRespository(resourceRepository);
        }
        else
        {
           return new UserRepository(principal.Identity, resourceRepository);
        }
    }
    

    The reason that I don't want to use AuthorizeAttribute to do per resource authentication is that different resources may have different code to check ownership, it's hard to centralized the code in one attribute and it requires extra DB operations which is not really necessary. Another concern is that AuthroizeAttribute happens before parameter binding, so you need to make sure the parameter of the action is coming from route data. Otherwise, for example, from a post body, you won't be able to get the parameter value.

提交回复
热议问题