ASP.NET 基于查询字符串的核心授权

ASP.NET Core Authorization based on query string

我的 Web API 中有一个端点,如下所示:

api/customers?salesRepId=123

现在,如果我不在查询字符串中提供 salesRepId,我希望能够吸引所有客户。如果提供了 salesRepId,我只想拉取销售代表的客户。

只有管理员可以查看所有客户,这意味着当我以 salesRepId 123 登录并在没有查询字符串的情况下调用 api/customers 时,API 应该以 401(未授权)响应) 错误。

如何在 ASP.NET Core 2.0 Web API 中执行此操作?

另一种选择是暴露 2 个端点,我希望避免这种情况。

我假设 api/customers 的控制器看起来类似于以下内容(暂时忽略 return 类型):

[HttpGet("customers/{salesRepId}")]
public JsonResult Customers(int salesRepId)

而且我还假设您正在以某种方式单独处理授权(可能使用属性或某些中间件)。

如果是这样,我会将 salesRepId 参数更改为可为 null 的 int (here is a little about Nullable types, if you've not used them before),方法签名如下:

[HttpGet("customers/{salesRepId}")]
public JsonResult Customers(int? salesRepId)

然后我会检查 salesRepId 是否有一个值(即它作为 QueryString 的一部分提供),方法是:

[HttpGet("customers/{salesRepId}")]
public JsonResult Customers(int? salesRepId)
{
  // userIsNotAuthorised is the name I'm giving to whatever
  // whatever check you are making that the user is authorised
  if (!salesRepId.HasValue && userIsNotAuthorised)
  {
    // return 401
  }
    // user is either authorised or has supplied a salesRepId or both
}

您还可以更改路由属性以匹配如下内容:

[HttpGet("customers/{salesRepId:int?}")]
public JsonResult Customers(int salesRepId = -1)

请注意,在本例中我必须提供默认选项。这将改变我们需要如何更改方法主体中的检查以匹配如下内容:

[HttpGet("customers/{salesRepId:int?}")]
public JsonResult Customers(int salesRepId = -1)
{
  // userIsNotAuthorised is the name I'm giving to whatever
  // whatever check you are making that the user is authorised
  if (salesRepId == -1 && userIsNotAuthorised)
  {
    // return 401
  }
    // user is either authorised or has supplied a salesRepId or both
}

我个人更喜欢尽可能使用 Nullable 类型。这是因为在第二个示例中,我们依赖于 -1(我们将其用作 magic number,这是一种反模式)。

您不需要 salesRepId 除了过滤。

当代表登录时,对 api/customers 的调用应该 return 管理员的所有客户和代表的所有客户。

调用 api/customers?salesRepId=123 应用相同的验证(可以通过 policy based authentcation 检查声明或范围),但过滤结果(属于一个代表的所有客户。

当管理员致电 api/customers?salesRepId=123 时,他收到的结果与销售代表致电 api/customersapi/customers?salesRepId=123 时收到的结果相同,但当销售代表致电 api/customers?salesRepId=456 时,他 returns 一个空结果(因为他的结果被 456 过滤结果为空)。

或者换句话说:如果用户是某种管理用户,控制器会将登录用户的 id 设置为销售代表过滤器。

这样您就不必以不同方式处理它,API 对每个用户的行为都相同。

不要忘记,RESTful 应用程序中的查询可以通过应用过滤来减少数据量。

或者,有两个路由操作的路由。 api/customers 具有我上面描述的行为和 api/salesrepresentative/123/customersapi/my/customers(具体暗示它的范围缩小到登录用户)。这清楚地表明它是两种不同类型的资源。

第一个是所有客户的集合,而第二个是给定代表的所有客户。