如何自定义的ASP.NET Web API AuthorizeAttribute不寻常的要求 [英] How to Customize ASP.NET Web API AuthorizeAttribute for Unusual Requirements

查看:2137
本文介绍了如何自定义的ASP.NET Web API AuthorizeAttribute不寻常的要求的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我继承的 System.Web.Http.AuthorizeAttribute 以创建自定义的授权/认证程序,以满足Web应用程序的一些不寻常的要求使用ASP.NET MVC 4开发这增加了安全性使用Ajax的网络API从Web客户端调用。的要求是:

I am inheriting from System.Web.Http.AuthorizeAttribute to create a custom authorization/authentication routine to meet some unusual requirements for a web application developed using ASP.NET MVC 4. This adds security to the Web API used for Ajax calls from the web client. The requirements are:


  1. 的用户必须在每次登录他们进行交易,以验证
    别人还没有走到工作站有人后
    登录并走开了。

  2. 角色不能​​分配到的节目时间Web服务的方法。
    他们必须在运行时被分配以使管理员能
    配置此。这个信息被存储在系统数据库中。

该网站的客户端是一个单页应用(SPA)这样典型的窗体身份验证不工作这么好,但我想重用尽可能多的ASP.NET安全框架,因为我能满足要求。定制的 AuthorizeAttribute 在确定什么样的角色都与Web服务方法相关的伟大工程的要求2。我接受三个参数,应用程序名称,资源名称和运作,以确定哪些角色与方法关联。

The web client is a single page application (SPA) so the typical forms authentication does not work so well, but I am trying reuse as much of the ASP.NET security framework as I can to meet the requirements. The customized AuthorizeAttribute works great for requirement 2 on determining what roles are associated with a web service method. I accept three parameters, application name, resource name and operation to determine which roles are associated with a method.

public class DoThisController : ApiController
{
    [Authorize(Application = "MyApp", Resource = "DoThis", Operation = "read")]
    public string GetData()
    {
        return "We did this.";
    }
}

我重写 OnAuthorization 方法来获得角色和用户进行身份验证。由于用户被认证为每个事务我减少通过在同一步骤进行认证和授权的来回震颤。我用它在传递HTTP头中加密凭据基本身份验证您可以通过Web客户端的用户凭据。所以,我的 OnAuthorization 方式是这样的:

I override the OnAuthorization method to get the roles and authenticate the user. Since the user has to be authenticated for each transaction I reduce the back and forth chatter by performing authentication and authorization in the same step. I get the users credentials from the web client by using basic authentication which passes the encrypted credentials in the HTTP header. So my OnAuthorization method looks like this:

public override void OnAuthorization(HttpActionContext actionContext)
{

     string username;
     string password;
     if (GetUserNameAndPassword(actionContext, out username, out password))
     {
         if (Membership.ValidateUser(username, password))
         {
             FormsAuthentication.SetAuthCookie(username, false);
             base.Roles = GetResourceOperationRoles();
         }
         else
         {
             FormsAuthentication.SignOut();
             base.Roles = "";
         }
     }
     else
     {
         FormsAuthentication.SignOut();
         base.Roles = "";
     }
     base.OnAuthorization(actionContext);
 }

GetUserNameAndPassword 检索来自HTTP标头的凭据。然后,我使用 Membership.ValidateUser 以验证凭据。我有一个自定义的成员资格提供程序和角色提供插在打了一个自定义数据库。如果用户通过验证我然后检索该资源和操作的角色。从那里我使用基本的 OnAuthorization 以完成授权过程。这里是它打破了。

GetUserNameAndPassword retrieves the credentials from the HTTP header. I then use the Membership.ValidateUser to validate the credentials. I have a custom membership provider and role provider plugged in to hit a custom database. If the user is authenticated I then retrieve the roles for the resource and operation. From there I use the base OnAuthorization to complete the authorization process. Here is where it breaks down.

如果用户通过验证我用的是标准的窗体身份验证方法登录(FormsAuthentication.SetAuthCookie)用户,如果他们失败,我登入出来(FormsAuthentication.SignOut)。但问题似乎是,基地的 OnAuthorization 类没有访问的主要被更新,以便 IsAuthenticated 设置为正确的值。它总是一个落后一步。我的猜测是,它是使用没有更新,直到有一个往返于Web客户端缓存的一些价值。

If the user is authenticated I use the standard forms authentication methods to log the user in (FormsAuthentication.SetAuthCookie) and if they fail I log them out (FormsAuthentication.SignOut). But the problem seems to be that base OnAuthorization class does not have access to Principal that is updated so that IsAuthenticated is set to the correct value. It is always one step behind. And my guess is that it is using some cached value that does not get updated until there is a round trip to the web client.

因此​​,所有这一切导致了我的具体问题是,有另一种方式来设置的 IsAuthenticated 以当前的主要的正确值不使用cookies吗?在我看来,这饼干并不真正适用于这种特定情况下,我每次都进行身份验证。我之所以知道的 IsAuthenticated 未设置为正确的值我也覆盖的 HandleUnauthorizedRequest 方法如下:

So all of this leads up to my specific question which is, is there another way to set IsAuthenticated to the correct value for the current Principal without using cookies? It seems to me that cookies do not really apply in this specific scenario where I have to authenticate every time. The reason I know IsAuthenticated is not set to the correct value is I also override the HandleUnauthorizedRequest method to this:

 protected override void HandleUnauthorizedRequest(HttpActionContext filterContext)
 {
     if (((System.Web.HttpContext.Current.User).Identity).IsAuthenticated)
     {
         filterContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
     }
     else
     {
         base.HandleUnauthorizedRequest(filterContext);
     }
 }

这让我返回严禁Web客户端,如果故障是由于授权而非认证的,它可以做出相应的反应状态code。

This allows me to return a status code of Forbidden to the web client if the failure was because of authorization instead of authentication and it can respond accordingly.

那么,什么是将 IsAuthenticated 当前的原理在这种情况下?

So what is the proper way to set IsAuthenticated for the current Principle in this scenario?

推荐答案

有关我的情况最好的解决办法似乎是绕过基地的 OnAuthorization 完全。因为我有验证每次饼干和缓存的原则,是没有多大用处。因此,这里是我想出了解决办法:

The best solution for my scenario appears to be bypass the base OnAuthorization completely. Since I have to authenticate each time cookies and caching the principle are not of much use. So here is the solution I came up with:

 public override void OnAuthorization(HttpActionContext actionContext)
 {

     string username;
     string password;
     if (GetUserNameAndPassword(actionContext, out username, out password))
     {
         if (Membership.ValidateUser(username, password))
         {
             if (!isUserAuthorized(username))
                 actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden);
         }
         else
         {
             actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);
         }
     }
     else
     {
         actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.BadRequest);
     }
 }

我开发我自己的方法来验证名为 isUserAuthorized ,我不使用基本的 OnAuthorization 任何更多,因为它会检查当前的原理看它是否 isAuthenticated IsAuthenticated 只允许得到,因此我不知道怎么回事,设置它,我似乎并不需要电流原理。测试了这一点,它工作正常。

I developed my own method for validating the roles called isUserAuthorized and I am not using the base OnAuthorization any more since it checks the current Principle to see if it isAuthenticated. IsAuthenticated only allows gets so I am not sure how else to set it, and I do not seem to need the current Principle. Tested this out and it works fine.

如果任何人有一个更好的解决方案,也可以看到与此这一项的任何问题仍感兴趣。

Still interested if anyone has a better solution or can see any issues with this this one.

这篇关于如何自定义的ASP.NET Web API AuthorizeAttribute不寻常的要求的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆