如何使 ASP.NET Web API 正确响应 403 或 401?
Posted
技术标签:
【中文标题】如何使 ASP.NET Web API 正确响应 403 或 401?【英文标题】:How to make ASP.NET Web API respond 403 or 401 appropriately? 【发布时间】:2013-03-21 23:48:35 【问题描述】:我正在使用 ASP.NET Web API。而且我确实喜欢添加属性以指定对 API 控制器的访问级别的能力,如下所示:
[Authorize]
public IEnumerable<Activity> Get()
到目前为止一切都很好,但是当我使用角色时,这个概念就崩溃了。
[Authorize(Roles = "Manager")]
public IEnumerable<Activity> Get()
我的用户可能在不久前登录了系统,然后在某个时候他们点击了对他们“禁止”的资源。用户尝试再次登录是没有意义的。由于他们的合法帐户无权访问该 URL。但目前他们得到的是 401(未经授权)而不是 403(禁止),就好像他们用错误的帐户登录一样。但用户只有一个帐号,并不打算让用户申请属于其他人的帐号。
还有其他人处理过这个问题吗?有谁知道如何解决这一问题?我非常愿意编写代码来解决这个问题,但我目前不知道从哪里开始。
【问题讨论】:
【参考方案1】:阅读 Parv 的建议,我创建了以下名为 [WebApiAuthorize] 的自定义过滤器。
关键是 HandleUnauthorizedRequest() 方法。当代码在这个方法中执行时,这是因为用户“出于某种原因”未经授权......所以现在我们只需确定“为什么”......然后:
-
为默认行为调用基方法(返回 401).... 或....
使用 403 返回我们自己的响应。
如您所见,它在适当的时候返回 403(经过身份验证,但未授权)。
public class WebApiAuthorizeAttribute : AuthorizeAttribute
protected override void HandleUnauthorizedRequest(HttpActionContext ctx)
if (!ctx.RequestContext.Principal.Identity.IsAuthenticated)
base.HandleUnauthorizedRequest(ctx);
else
// Authenticated, but not AUTHORIZED. Return 403 instead!
ctx.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
要使用,只需将自定义过滤器扔到控制器或类似这样的操作上.....
[WebApiAuthorize(Roles = "YourRoleA,YourRoleB")]
public class AdminController : ApiController
public List<Admin> GetAdmins()
...
【讨论】:
小改进。您应该检查 Principal 或 Identity 是否为 null,否则当请求未提供凭据时,您可能会收到 NullReferenceException。protected bool IsAuthenticated(HttpActionContext ctx) var principal = ctx.RequestContext.Principal; return principal != null && principal.Identity != null && principal.Identity.IsAuthenticated;
【参考方案2】:
我做了一些研究,并为我编写了一个解决方案。我在 System.Web.Mvc 上找到了两个不同的 Authorize 属性,在 System.Web.Http 上找到了第二个。第一个适用于常规 MVC4 应用程序,第二个适用于用于 Web 服务的 MVC4 的 WebAPI 部分,包括 RESTful 接口。所以我用了第二个。
我决定查看 codeplex 的 Authorize Attribute Source 代码。我发现了这个:
protected virtual bool IsAuthorized(HttpActionContext actionContext)
if (actionContext == null)
throw Error.ArgumentNull("actionContext");
IPrincipal user = Thread.CurrentPrincipal;
if (user == null || !user.Identity.IsAuthenticated)
return false;
if (_usersSplit.Length > 0 && !_usersSplit.Contains(user.Identity.Name, StringComparer.OrdinalIgnoreCase))
return false;
if (_rolesSplit.Length > 0 && !_rolesSplit.Any(user.IsInRole))
return false;
return true;
很容易看出身份验证和访问是如何混为一谈的,因为它们都具有返回 false 的相同效果。
这是我写的new AuthorizeAttribute,当用户或角色不匹配时返回 403。这样您就可以避免获得本机登录窗口。它包括以下代码。
if (!IsAuthorized(actionContext))
HandleUnauthorizedRequest(actionContext);
if (!IsAllowed(actionContext))
HandleForbiddenRequest(actionContext);
【讨论】:
不情愿地投了赞成票;您应该在此处引用HandleUnathorizedRequest()
和/或HandleForbiddenRequest()
的代码,这样我们就不必按照您的要点链接。【参考方案3】:
你可以做一个自定义Authorize attribute
然后处理
AuthorizeCore
和 OnAuthorizationFailed
在后一个中,您可以发送您喜欢的任何回复
有一个look here
【讨论】:
修改 AuthorizeAttribue 就是答案。该特定示例是修改 System.Web.Mvc 而不是 System.Web.Http,因为我使用的是 WebAPI。 我以为你想创建一个自定义属性来发回你喜欢的 Http 状态代码 这就是我所做的,我继承自 System.Web.Http.AuthorizeAtribute。不是来自 System.Web.Mvc.AuthorizeAtribute ,这是您指出的文章所指的内容。 如果您想处理请求授权失败后发送的自定义代码,或者您可以从 AutorizeFilterAttribute 继承以上是关于如何使 ASP.NET Web API 正确响应 403 或 401?的主要内容,如果未能解决你的问题,请参考以下文章
如何自定义 ASP .NET Web API JWT 令牌响应?
如何使 ASP.NET Web API Web 服务在本地网络中可用
如何使 ASP.NET Core Web API 操作异步执行?
使用 Owin 时无法使 ASP.NET Web API 2 帮助页面正常工作