【问题标题】:Returning a 403 from a webapi2 controller从 webapi2 控制器返回 403
【发布时间】:2015-09-04 21:41:01
【问题描述】:

我的 API 有以下路由

GET:api/部门

GET:api/departments/{departmentID}/employees

第二条路由映射到下面的控制器动作

public IEnumerable<Employee> Get(int departmentID)
{
  return GetEmployees(departmentID);
}

可能会使用不存在或用户无权访问的部门ID 调用此路由。发生这种情况时,正确的处理方法是什么?目前,我已修改控制器操作以返回 403,如下所示

public HttpResponseMessage Get(int departmentID)
{
  var isDepartmentValid = CheckIfDepartmentIsAccessible(username, departmentID);
  if(!isDepartmentValid)
  {
    return Request.CreateResponse(HttpStatusCode.Forbidden);
  }

   Request.CreateResponse(HttpStatusCode.OK, GetEmployees(departmentID));
}

这是正确的做法吗?似乎方法签名的更改使得更难理解从控制器操作返回的内容类型。有没有办法让方法签名保持不变但如果需要仍然返回 403?

【问题讨论】:

  • 如果部门不存在,我实际上建议抛出 404 而不是 403,如果是权限问题,则抛出 403。

标签: c# asp.net-web-api2


【解决方案1】:

要添加到 Rob Davis 的答案,我建议您这样做,这样您就不需要更改方法的签名,并且返回的响应对客户更有意义:

public IEnumerable<Employee> Get(int departmentID)
{
   try
   {
      return GetEmployees(departmentID);
   }
   catch(Exception ex) //assuming invalid dept or unauthorized throw Argument & Security Exceptions respectively
   {
        if(ex is SecurityException)
            throw new HttpResponseException(HttpStatusCode.Forbidden);
        else if(ex is ArgumentException)
            throw new HttpResponseException(HttpStatusCode.NotFound);
        else
             //handle or throw actual unhandled exception
    }
}

这假设您正在使用异常,但显然可以进行任何其他类型的检查以查看部门是否存在或他们是否有权访问。然后返回正确的响应。由于这是一个 WebAPI,性能损失可以忽略不计,因为您最大的瓶颈很可能是网络本身。

【讨论】:

    【解决方案2】:

    您可以执行以下操作:

    public IEnumerable<Employee> Get(int departmentID)
    {
        var isDepartmentValid = CheckIfDepartmentIsAccessible(username, departmentID);
        if (!isDepartmentValid)
        {
            throw new HttpResponseException(HttpStatusCode.Forbidden);
        }
    
        return Request.CreateResponse(HttpStatusCode.OK, GetEmployees(departmentID));
    }
    

    【讨论】:

    • 我确实在网上找到了这个解决方案,但出于性能原因跳过了它,尽管我可能错了。抛出未处理的异常会影响性能和可扩展性吗?
    • @user1 从技术上讲,使用 HttpResponseException 可能会降低性能,但还不足以让我避免走这条路。您似乎不是在创建实时性能应用程序,因此减速可以忽略不计。这实际上并不是一个未处理的异常,因为 ASP.NET 管道会处理它并返回您想要发回的 http 响应代码。
    【解决方案3】:

    对我来说,放置各种身份验证/授权的最佳位置是在 OWIN 中间件或一些授权操作过滤器中;但取决于您的要求,因为如果您没有更多需要身份验证的路由,我可能会保留解决方案,并在控制器操作本身内部进行检查。

    【讨论】:

    • 如何在 OWIN 中间件中验证控制器参数?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2014-07-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-21
    • 2012-02-21
    相关资源
    最近更新 更多