资源在基于.NET的授权资源、NET

2023-09-04 01:54:17 作者:狂傲゛俯视全世界

假设你有一个的.NET Web API,以占用资源(INT RESOURCEID)的行动。这个动作(与指定id)应只被授权与该id(资源例如可以是由用户写入一个博文)相关联的用户。

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 that id (the resource could for instance be a blogpost written by the user).

这可以以许多方式来解决,但下面给出一个例子。

This could be solved in many ways, but an example is given below.

    public Resource GetResource(int id)
    {
        string name = Thread.CurrentPrincipal.Identity.Name;
        var user = userRepository.SingleOrDefault(x => x.UserName == name);
        var resource = resourceRepository.Find(id);

        if (resource.UserId != user.UserId)
        {
            throw new HttpResponseException(HttpStatusCode.Unauthorized);
        }

        return resource;
    }

在用户已经被认证通过某种mechanicm的。

where the user has been authenticated by some sort of mechanicm.

现在,让我们说,我也想的用户,例如,管理员的类型,被授权消费终端(具有相同的ID)。这个用户没有任何直接关系到资源,但的确有,因为它的类型(或角色)的授权。这可以通过只检查,如果用户是admin类型和返回的资源来解决。

Now, let's say that I also want a user of, for instance, an admin type, to be authorized to consume the endpoint (with the same id). This user does not have any direct relation to the resource but does have authorization because of it's type (or role). This could be solved by just checking if the user is of admin type and the return the resource.

有没有办法集中这在某种程度上,这样我就不必写权限code的每一个动作?

Is there any way to centralize this in a way so that I don't have to write authorization code in every action?

修改 基于我认为我要澄清我的问题的答案。

Edit Based on the answers I think I have to clarify my question.

什么我真的后,一些机制,使得有可能有​​基于资源的授权,但同时允许某些用户还消耗相同的端点和相同的资源。下面的行动将解决这个问题这个特定端点和这个特定的角色(管理员)。

What I am really after is some mechanism that makes it possible to have resource based authorization, but at the same time allow some users to also consume the same endpoint and the same resource. The action below would solve this for this specific endpoint and for this specific Role (Admin).

    public Resource GetResource(int id)
    {
        string name = Thread.CurrentPrincipal.Identity.Name;
        var user = userRepository.SingleOrDefault(x => x.UserName == name);
        var resource = resourceRepository.Find(id);

        if (!user.Roles.Any(x => x.RoleName == "Admin" || resource.UserId != user.UserId)
        {
            throw new HttpResponseException(HttpStatusCode.Unauthorized);
        }

        return resource;
    }

我以后的事情是一些通用的方法来解决这个问题,使我没有写两个不同的端点有异曲同工之妙,或写在每一个端点资源的具体code。

The thing I am after is some generic way to solve this problem so that I don't have to write two different endpoints with the same purpose or write resource specific code in every endpoint.

推荐答案

对于资源的授权,我建议使用的根据声明身份并嵌入用户ID作为索赔。写一个扩展方法来读取身份索赔。所以样品code将是这样的:

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;
}

如果您想进一步简化code更多,你可以写它知道用户数据和资源库,集中了code一UserRepository。在code将是这样的:

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);
}

有关基于角色的授权的 AuthorizeAttribute 将处理它最好的地方,你最好使用单独行动或控制器的。

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);
}

如果OP确实想使用一个单一的行动来处理不同类型的用户,我个人preFER使用用户系统信息库的工厂。该行动code将是:

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);
    }
}

这是我不希望使用AuthorizeAttribute每个资源认证做的原因是,不同的资源可能有不同的code检查所有权,很难集中在一个属性中的code,它需要额外的数据库操作是不是真的有必要。 另一个值得关注的是,AuthroizeAttribute前参数绑定情况,所以你需要确保动作的参数是从路由数据的到来。否则,例如,从一个职位身上,你将无法得到的参数值。

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.

 
精彩推荐
图片推荐