.net中基于资源的授权

假设你有一个带有GetResource(int resourceId)操作的.net web api.此操作(具有指定的ID)应仅对与该ID相关联的用户授权(该资源可能例如是由用户编写的博客文件).

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

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

用户已通过某种机制进行身份验证.

现在,我们也想要一个用户,例如管理类型,被授权使用端点(具有相同的id).该用户与资源没有任何直接关系,但是由于它的类型(或角色)而具有授权.这可以通过检查用户是否具有管理类型并返回资源来解决.

有没有办法集中这个方式,以便我不必在每个动作中编写授权码?

编辑
根据答案,我想我必须澄清我的问题.

我真正的追求是一些机制,使得有可能获得基于资源的授权,但同时允许一些用户也使用相同的端点和相同的资源.下面的操作将为此特定端点和此特定角色(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;
    }

我所追求的是一些通用的方法解决这个问题,所以我不必用同样的目的编写两个不同的端点,也可以在每个端点写入特定于资源的代码.

解决方法

对于基于资源的授权,我建议使用 claim based identity并嵌入用户ID作为声明.编写一个扩展方法来从身份读取权利要求.所以示例代码将如下所示:
public Resource GetResource(int id)
{
     var resource = resourceRepository.Find(id);
    if (resource.UserId != User.Identity.GetUserId())
    {
        throw new HttpResponseException(HttpStatusCode.Unauthorized);
    }

    return resource;
}

如果要进一步简化代码,可以编写一个用户数据库(UserRepository),该用户资料库知道用户数据和资源存储库以集中代码.代码将如下所示:

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

对于基于角色的授权,AuthorizeAttribute将是处理它的最佳位置,您最好使用单独的操作或控制器.

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

[编辑]
如果OP想要使用一个单独的操作来处理不同类型的用户,我个人更喜欢使用用户存储库工厂.行动代码将是:

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

扩展方法将是:

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对资源进行身份验证的原因是,不同的资源可能会有不同的代码来检查所有权,所以很难将代码集中在一个属性中,并且需要额外的DB操作,这并不是真的必要的.另一个问题是AuthroizeAttribute发生在参数绑定之前,因此您需要确保操作的参数来自路由数据.否则,例如,从邮件正文中,您将无法获取参数值.

相关文章

### 创建一个gRPC服务项目(grpc服务端)和一个 webapi项目(...
一、SiganlR 使用的协议类型 1.websocket即时通讯协议 2.Ser...
.Net 6 WebApi 项目 在Linux系统上 打包成Docker镜像,发布为...
一、 PD简介PowerDesigner 是一个集所有现代建模技术于一身的...
一、存储过程 存储过程就像数据库中运行的方法(函数) 优点:...
一、Ueditor的下载 1、百度编辑器下载地址:http://ueditor....