我有一个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%的实际代码。
在每个控制器中,我都有很多很多权限检查。我已经在使用身份验证和授权;事实并非如此。在这里,它取决于用户请求访问的项目。
我想要做的是从控制器中删除检查并降低代码的复杂性。
我已经尝试过创建自定义策略,自定义属性和自定义中间件,但是检查数据库两次要慢很多,而且它对降低复杂性几乎没有作用。
是否有关于我遗漏的此类问题的指导原则?
答案 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;将获得许多功能,但不是所有功能。因此,一旦您创建了您的功能,您需要使它们变得简单,负责,独特和个性化。
考虑使用此图像进行可视化:
伪可能是这样的:
注意:可能有一个适用于所有类型用户的常见功能列表。
答案 2 :(得分:1)
你有两种方法来检查权限,首先是应用程序端(控制器不是一个好选择,如果你至少有帮助器或BaseController将是好的)。您可以尝试在基本控制器中覆盖OnActionExecuting并检查权限
和第二:
如果您正在使用Mssql数据库或类似的,您可以检查数据库端(创建函数或存储过程)的权限,返回0或1(0表示用户没有权限)
答案 3 :(得分:1)
permission checks/validations
逻辑解耦。但两次检查数据库的速度要慢很多
您可以在HttpContext.Items
中存储来自第一次数据库调用的数据(假设在中间件中),然后在操作中再次从上下文而不是数据库中获取该数据。
HttpContext.Items
:获取或设置可用于在此请求范围内共享数据的键/值集合。