我从System.Web.Http.AuthorizeAttribute继承以创建自定义授权/身份验证 routine ,以满足使用ASP.NET MVC 4开发的Web应用程序的一些特殊要求.这为Web客户端的AJAX调用使用的Web API增加了安全性.要求是:

  1. 用户必须在每次执行事务时登录以进行验证
  2. 不能在编程时将角色分配给Web服务方法. 必须在运行时分配它们,以便管理员可以 对此进行配置.此信息存储在系统数据库中.

Web客户端是single page application (SPA),因此典型的窗体身份验证不能很好地工作,但我正在try 尽可能多地重用ASP.NET安全框架以满足要求.定制的AuthorizeAttribute在确定哪些角色与Web服务方法相关联方面非常适合需求2.我接受三个参数(应用程序名称、资源名称和操作)来确定哪些角色与方法相关联.

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

我重写OnAuthorization方法来获取角色并验证用户.由于每个事务都必须对用户进行身份验证,因此我通过在同一步骤中执行身份验证和授权来减少来回的喋喋不休.我通过使用基本身份验证从web客户端获取用户凭据,该身份验证在HTTP头中传递加密的凭据.所以我的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验证凭证.我有一个自定义的成员资格提供程序和角色提供程序插入到一个自定义数据库.如果用户经过身份验证,那么我将检索资源和操作的角色.在此基础上,我使用base OnAuthorization完成授权过程.这就是它的故障所在.

如果用户通过了身份验证,我将使用标准的窗体身份验证方法让用户登录(FormsAuthentication.SetAuthCookie),如果失败,我将他们注销(FormsAuthentication.SignOut).但问题似乎是,基数OnAuthorization类无法访问更新后的Principal,因此IsAuthenticated被设置为正确的值.它总是落后一步.我的猜测是,它使用的是一些缓存值,这些值在到Web客户端的往返行程之前不会更新.

所有这些都引出了我的具体问题,那就是,有没有其他方法可以在不使用cookie的情况下将IsAuthenticated设置为当前Principal的正确值?在我看来,Cookie并不真正适用于我每次都必须进行身份验证的特定场景.我知道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客户端返回禁止的状态代码,并且它可以相应地响应.

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

推荐答案

对于我的情况,最好的解决方案似乎是完全绕过基数OnAuthorization.由于我每次都必须进行身份验证,因此cookie和缓存原则用处不大.所以这是我想出的解决方案:

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,因为它会判断当前的Principle是否为isAuthenticated.IsAuthenticated只允许GET,所以我不确定如何设置它,而且我似乎不需要当前的Principle.对此进行了测试,运行良好.

如果有人有更好的解决方案,或者能看到这个解决方案的任何问题,我仍然很感兴趣.

Asp.net相关问答推荐

属性包含破折号的 ServiceStack 请求对象?

如何在asp.net中单击按钮的新选项卡中打开页面?

如何在 ASP.NET 全球化中配置不变文化?

asp.net、url 重写模块和 web.config

我可以在 .net 核心中使用 Entity Framework 6(非核心)吗?

如何使用 jQuery 设置 outerHTML

如何将 Castle Windsor 与 ASP.Net Web 表单一起使用?

使用 JavaScript 更改 ASP.NET 标签的可见性

如何检测 ASP.net 应用程序中的 SqlServer 连接泄漏?

MvcBuildViews true 与 ASP.NET MVC 2 中的实体框架

AddDefaultTokenProviders:它是什么以及如何使用那些默认提供者?

IIS 中的 existingResponse="PassThrough" 是什么意思?

获取页面上特定类型的所有 Web 控件

如何从 Asp.net Mvc-3 发送邮箱?

修改 web.config 时如何防止 ASP.NET 应用程序重新启动?

如何判断用户代理是 ipad 还是 iphone?

HttpContext.Current 在 MVC 4 项目中未解决

SQLServer 与 StateServer 的 ASP.NET 会话状态性能

在 ASP.NET 标识中添加角色

将 HTML 字符串转换为图像