如何自定义的ASP.NET Web API AuthorizeAttribute不寻常的要求(How

2019-06-18 08:38发布

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

  1. 用户必须在每次进行交易,以验证别人还没有走到有人登录并走开后工作站一次登录。
  2. 角色不能分配到节目时间的Web服务方法。 他们必须在运行时分配,所以管理员可以配置此。 此信息存储在系统数据库中。

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

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

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

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完成授权过程。 这里是它打破了。

如果用户通过验证我用的是标准的形式验证方法进行登录(FormsAuthentication.SetAuthCookie)的用户,如果他们失败,我将他们注销(FormsAuthentication.SignOut)。 但问题似乎是基地OnAuthorization类没有获得校长IsAuthenticated设置为正确的值被更新。 它始终是一个落后一步。 我的猜测是,它使用的是没有更新,直到有一个往返于web客户端缓存的一些价值。

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

 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客户端,如果故障是由于授权,而不是认证的,它可以做出相应的响应状态代码。

那么,什么是设置IsAuthenticated在这种情况下当前原理的正确方法?

Answer 1:

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

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只允许得到,所以我不知道怎么回事设置它,我似乎并不需要电流原理 。 测试了这一点,它工作正常。

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



Answer 2:

要添加到已接受的答案:当前检查源代码(aspnetwebstack.codeplex.com)为System.Web.Http.AuthorizeAttribute ,它看起来像文档过时。 基地OnAuthorization()只是调用/检查私有静态SkipAuthorization()如果它只是检查AllowAnonymousAttribute在上下文中使用,以绕过认证检查的其余部分)。 然后,如果没有跳过, OnAuthorization()调用公共IsAuthorized()如果该调用失败,然后调用受保护的虚拟HandleUnauthorizedRequest() 而这一切,它...

public override void OnAuthorization(HttpActionContext actionContext)
{
    if (actionContext == null)
    {
        throw Error.ArgumentNull("actionContext");
    }

    if (SkipAuthorization(actionContext))
    {
        return;
    }

    if (!IsAuthorized(actionContext))
    {
        HandleUnauthorizedRequest(actionContext);
    }
}

展望内IsAuthorized()这其中的原理是对角色和用户检查。 因此,覆盖IsAuthorized()与你有什么上面,而不是OnAuthorization()是要走的路。 话又说回来,你还是不得不重写可能既OnAuthorization()HandleUnauthorizedRequest()反正来决定何时返回401 VS 403的响应。



Answer 3:

要添加到由凯文绝对正确的答案,我想说,我可能略有修改,以充分利用现有的.NET框架路径响应对象,以确保在框架(或其他消费者)下游的代码不会受到负面影响由无法预测有些怪异的癖好。

具体而言,这意味着使用此代码:

actionContext.Response = actionContext.ControllerContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, REQUEST_NOT_AUTHORIZED);

而不是:

actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);

其中REQUEST_NOT_AUTHORIZED是:

private const string REQUEST_NOT_AUTHORIZED = "Authorization has been denied for this request.";

我把那个stringSRResources.RequestNotAuthorized在.NET框架的定义。

伟大的答案凯文! 我实现了我的非常相同的方式,因为执行OnAuthorization在基类中没有任何意义,因为我确认这是自我们的应用程序中的HTTP头居然不希望在所有检查主要因为没有一个。



文章来源: How to Customize ASP.NET Web API AuthorizeAttribute for Unusual Requirements