如何处理依赖于请求的数据的授权

时间:2018-02-23 04:37:02

标签: c# asp.net design-patterns asp.net-core architecture

我有一个API项目,它具有很多访问限制,具体取决于用户请求的项目。例如,让我们说我有这样的行动:

[HttpPut]
public async Task<IActionResult> EditItem([FromBody]Item editedItem)
{
    var item = await db.Items.SingleOrDefaultAsync(i => i.Id == editedItem.Id);

    if (item == null) // There is already pre-filter on the DB.
        return Unauthorized();

    if (item.Status == ItemStatus.Closed)
        return Unauthorized();

    if (item.Owner != _currentUser)
        return Unauthorized();

    // Say the normal user only have permissions to edit items on the Status "Added"
    if (!(_currentUser is Manager) && editedItem.Status == item.Status.Open)
        return Unauthorized();

    // Edit the data...

    await db.SaveChangesAsync();

    return Ok();
}

软件正在增长,这开始变得嘈杂而且不干净。这些操作有90%的权限检查和10%的实际代码。

在每个控制器中,我都有很多很多权限检查。我已经在使用身份验证和授权;事实并非如此。在这里,它取决于用户请求访问的项目。

我想要做的是从控制器中删除检查并降低代码的复杂性。

我已经尝试过创建自定义策略,自定义属性和自定义中间件,但是检查数据库两次要慢很多,而且它对降低复杂性几乎没有作用。

是否有关于我遗漏的此类问题的指导原则?

4 个答案:

答案 0 :(得分:3)

我建议制作某种授权服务来处理你需要的一切。例如:

public class AuthorizationService
{
    ...

    public Task<bool> IsAuthorizedAsync(Item item)
    {
        var authorized = item != null 
                            && item.Status != ItemStatus.Closed 
                            && item.Owner == _currentUser 
                            && (!(_currentUser is Manager) && editedItem.Status == item.Status.Open);
        return Task.FromResult(authorized);
    }
}

当然,您可以添加其他授权方法,这些方法可以对其他实体(不仅是Item)进行检查。

答案 1 :(得分:2)

考虑到您有5种类型的用户角色。每个角色都拥有基于规则集的自己的视图。

现在考虑一下,你有20个功能。 用户&#39;角色类型1&#39;将获得许多功能,但不是所有功能。因此,一旦您创建了您的功能,您需要使它们变得简单,负责,独特和个性化。

考虑使用此图像进行可视化:

str.zfill

伪可能是这样的:

  1. 检查登录的用户角色类型
  2. 根据用户角色类型获取每个功能或功能列表的允许ID
  3. 加载该用户的功能
  4. 注意:可能有一个适用于所有类型用户的常见功能列表。

答案 2 :(得分:1)

你有两种方法来检查权限,首先是应用程序端(控制器不是一个好选择,如果你至少有帮助器或BaseController将是好的)。您可以尝试在基本控制器中覆盖OnActionExecuting并检查权限

和第二:

如果您正在使用Mssql数据库或类似的,您可以检查数据库端(创建函数或存储过程)的权限,返回0或1(0表示用户没有权限)

答案 3 :(得分:1)

  • 控制器的动作应该有直截了当的快乐传递逻辑。
  • 应使用middlewares / filters将基于请求参数的任何permission checks/validations逻辑解耦。
  • 如果验证检查不依赖于请求参数,那么最好将逻辑移动到依赖服务并引发异常以停止进一步的请求执行。
  • 应使用中间件/过滤器将异常处理解耦。
  

但两次检查数据库的速度要慢很多

您可以在HttpContext.Items中存储来自第一次数据库调用的数据(假设在中间件中),然后在操作中再次从上下文而不是数据库中获取该数据。

  

HttpContext.Items:获取或设置可用于在此请求范围内共享数据的键/值集合。