Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/visual-studio-code/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asp.net AJAX和FormsAuthentication,如何防止FormsAuthentication覆盖HTTP 401?_Asp.net_Ajax_Http_Jquery_Forms Authentication - Fatal编程技术网

Asp.net AJAX和FormsAuthentication,如何防止FormsAuthentication覆盖HTTP 401?

Asp.net AJAX和FormsAuthentication,如何防止FormsAuthentication覆盖HTTP 401?,asp.net,ajax,http,jquery,forms-authentication,Asp.net,Ajax,Http,Jquery,Forms Authentication,在一个配置了FormsAuthentication的应用程序中,当用户在没有auth cookie或过期cookie的情况下访问受保护的页面时,ASP.NET发出HTTP 401 Unauthorized,然后FormsAuthentication模块在请求结束前截获此响应,并将其更改为找到的HTTP 302,设置HTTP头“Location:/path/loginurl”将用户代理重定向到登录页面,然后浏览器转到该页面并检索未受保护的登录页面,获得HTTP 200 OK 这确实是一个非常好的主

在一个配置了FormsAuthentication的应用程序中,当用户在没有auth cookie或过期cookie的情况下访问受保护的页面时,ASP.NET发出HTTP 401 Unauthorized,然后FormsAuthentication模块在请求结束前截获此响应,并将其更改为找到的HTTP 302,设置HTTP头“Location:/path/loginurl”将用户代理重定向到登录页面,然后浏览器转到该页面并检索未受保护的登录页面,获得HTTP 200 OK

这确实是一个非常好的主意,当时还没有考虑AJAX

现在,我的应用程序中有一个返回JSON数据的url,它需要对用户进行身份验证。一切正常,问题是如果auth cookie过期,当我的客户端代码调用服务器时,它将得到一个HTTP 200 OK和登录页面的html,而不是HTTP 401 Unauthorized(因为前面已经解释过)。然后我的客户端尝试将登录页面html解析为json,但失败了

接下来的问题是:如何处理来自客户端的过期身份验证?处理这种情况最优雅的解决方案是什么?我需要知道调用何时成功或失败,我想使用HTTP语义来完成

是否可以以安全的跨浏览器方式从客户端读取自定义HTTP头? 如果请求是AJAX请求,是否有方法告诉FormsAuthenticationModule不要执行重定向? 有没有一种方法可以像重写HTTP请求方法一样使用HTTP头重写HTTP状态

我需要表单身份验证,我希望避免重写该模块或编写自己的表单身份验证模块


问候。

我从其他帖子中大量窃取了这个答案,但一个想法可能是在登录页面上实现一个
HttpModule
(该链接中的说明)

您还可以修改该示例HttpModule,使其仅在通过AJAX发出请求时截获重定向,前提是当请求不是通过AJAX发出时,默认行为是正确的:

因此,大致如下:

class AuthRedirectHandler : IHttpModule
{
    #region IHttpModule Members

    public void Dispose()
    {

    }

    public void Init(HttpApplication context)
    {
        context.EndRequest+= new EventHandler(context_EndRequest);
    }


    void context_EndRequest(object sender, EventArgs e)
    {
        HttpApplication app = (HttpApplication)sender;
        if (app.Response.StatusCode == 302 
            && app.Request.Headers["X-Requested-With"] == "XMLHttpRequest"
            && context.Response.RedirectLocation.ToUpper().Contains("LOGIN.ASPX"))
        {
            app.Response.ClearHeaders();
            app.Response.ClearContent();
            app.Response.StatusCode = 401;
        }
    }

    #endregion
}
如果你的应用中还有其他合法的302重定向,你也可以确保重定向到你的实际登录页面

然后,您只需将以下内容添加到web.config:

  <httpModules>
    <add name="AuthRedirectHandler" type="SomeNameSpace.AuthRedirectHandler, SomeNameSpace" />
  </httpModules>


总之,我的回答是真实的原始想法,我只是从SO和web的其他部分收集了各种信息。

我也有同样的问题,必须在MVC中使用自定义属性。你可以很容易地将其应用到web表单中,如果你的所有页面都继承自s,你可以覆盖基本页面中的页面授权ome基本页(MVC中的全局属性允许相同的事情-覆盖应用程序中所有控制器/操作的OnAuthorization方法)

这是属性的外观:

public class AjaxAuthorizationAttribute : FilterAttribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationContext filterContext)
        {
            if (filterContext.HttpContext.Request.IsAjaxRequest()
                && !filterContext.HttpContext.User.Identity.IsAuthenticated
                && (filterContext.ActionDescriptor.GetCustomAttributes(typeof(AuthorizeAttribute), true).Count() > 0
                || filterContext.ActionDescriptor.ControllerDescriptor.GetCustomAttributes(typeof(AuthorizeAttribute), true).Count() > 0))
            {
                filterContext.HttpContext.SkipAuthorization = true;
                filterContext.HttpContext.Response.Clear();
                filterContext.HttpContext.Response.StatusCode = (int)System.Net.HttpStatusCode.Unauthorized;
                filterContext.Result = new HttpUnauthorizedResult("Unauthorized");
                filterContext.Result.ExecuteResult(filterContext.Controller.ControllerContext);
                filterContext.HttpContext.Response.End();
            }
        }
    }
请注意,您需要调用HttpContext.Response.End();否则您的请求将被重定向到login(我因此丢失了一些头发)

在客户端,我使用jQuery ajaxError方法:

var lastAjaxCall = { settings: null, jqXHR: null };
var loginUrl = "yourloginurl";

//...
//...

$(document).ready(function(){
    $(document).ajaxError(function (event, jqxhr, settings) {
            if (jqxhr.status == 401) {
                if (loginUrl) {
                    $("body").prepend("<div class='loginoverlay'><div class='full'></div><div class='iframe'><iframe id='login' src='" + loginUrl + "'></iframe></div></div>");
                    $("div.loginoverlay").show();
                    lastAjaxCall.jqXHR = jqxhr;
                    lastAjaxCall.settings = settings;
                }
            }
    }

}

这允许您的用户在会话到期时登录,而不会丢失上次显示的表单中键入的任何工作或数据。

我在实现时遇到问题。主要是,我的错误日志中充满了
发送HTTP头后服务器无法设置状态的
错误

我试图实现这个问题,但还是没有成功

在谷歌上搜索一下,我偶然发现了
SuppressFormsAuthenticationRedirect

如果.Net版本>=4.5,则可以将以下代码添加到自定义
AuthorizeAttribute
类的
HandleUnauthorizedRequest
方法中

public sealed class CustomAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
            filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
            base.HandleUnauthorizedRequest(filterContext);
            return;
        }

        base.HandleUnauthorizedRequest(filterContext);
        return;
    }
}

重要的部分是
if
块。如果您在.Net 4.5上并且已经有了自定义授权,这是最简单的操作。

好吧,正如我所说的,我正试图避免重写http模块,基本上是因为我不想维护另一段代码。另外,这个解决方案有点棘手,我想要的是重新编写是否删除对另一个端点的AJAX调用?我无法阻止所有http 302,那么使用http 401:P时我的情况将与现在类似。谢谢。1.您没有“重写http模块”,而是添加了一个非常短、简单的模块(它不处理任何实际的身份验证)处理未经授权的AJAX请求和2.正如我所说的,这个示例并没有包括所有可以想象的过滤器(在本例中甚至不需要)但是登录页面的302重定向要么是a)登录页面,要么是web.config中设置的值。这两个值中的任何一个都应该很容易计算出来并包含在条件中。我认为你不会找到一个包含不到十几行代码的解决方案。无论如何,这个话题已经讨论了一段时间了SP.NET表单:如果您碰巧正在使用MVC,并且注意实际寻找它们,那么也有很多更聪明的服务器端解决方案。我已经看到了所有这些解决方案,其中一些是旧的(2008年那一个),你认为我为什么明确地说我不想写一个模块来处理这个问题?也许在最新的asp.net版本中出现了一些新的东西。在前一段中有三个问题,这些问题就是本文的主题。如果可能的话……如果不快乐的日子也不错。我知道有1000种解决方法和大多数编程问题一样,我回答了你的问题:“如果请求是AJAX请求,有没有办法告诉FormsAuthenticationModule不要执行重定向?“很抱歉,您不满意这样做的方式是一个简单的HTTP模块。除此之外,没有人会在任何老问题出现时犹豫是否要添加新的解决方案。相信我,如果有一颗灵丹妙药的话,它会被钉在一个古老的棺材上
public sealed class CustomAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
            filterContext.HttpContext.Response.TrySkipIisCustomErrors = true;
            base.HandleUnauthorizedRequest(filterContext);
            return;
        }

        base.HandleUnauthorizedRequest(filterContext);
        return;
    }
}