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

时间:2018-01-06 17:51:49

标签: asp.net-web-api asp.net-core asp.net-core-2.0 asp.net-core-webapi

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

api/customers?salesRepId=123

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

只允许管理员查看所有客户,这意味着当我以salesRepId 123身份登录并调用不带查询字符串的api / customers时,API应响应401(未经授权)错误。

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

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

2 个答案:

答案 0 :(得分:2)

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

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

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

如果是这样,我会将salesRepId参数改为可为空的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,这是一种反模式。)

答案 1 :(得分:2)

除了过滤之外,您不需要salesRepId

当代表登录时,对api/customers的调用应返回所有客户以及代表的所​​有客户。

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

当管理员调用api/customers?salesRepId=123时,他会在调用api/customersapi/customers?salesRepId=123时收到与销售代表相同的结果,但当销售代表调用api/customers?salesRepId=456时,他会返回空结果(因为他的结果被456过滤了结果为空)。

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

通过这种方式,您不必以不同方式处理它,并且API对每个用户的行为都相同。

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

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

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