wake-up-neo.net

Behandeln des Sitzungszeitlimits bei Ajax-Anrufen

Ich mache einen Ajax-Aufruf mit Jquery zu einer ASP.vv-Controller-Aktion:

[AcceptVerbs(HttpVerbs.Post)]
        public ActionResult GetWeek(string startDay)
        {
            var daysOfWeek = CompanyUtility.GetWeek(User.Company.Id, startDay);
            return Json(daysOfWeek);
        }

Wenn die Sitzung abläuft, schlägt dieser Aufruf fehl, da das Benutzerobjekt in der Sitzung gespeichert wird. Ich habe ein benutzerdefiniertes Berechtigungsattribut erstellt, um zu überprüfen, ob die Sitzung verloren gegangen ist, und zur Anmeldeseite umzuleiten. Dies funktioniert gut für Seitenanfragen, jedoch nicht für Ajax-Anforderungen, da Sie von einer Ajax-Anforderung nicht weiterleiten können:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
    public class AuthorizeUserAttribute : AuthorizeAttribute
    {
        protected override bool AuthorizeCore(HttpContextBase httpContext)
        {
            if (!httpContext.Request.IsAjaxRequest())
            {//validate http request.
                if (!httpContext.Request.IsAuthenticated
                    || httpContext.Session["User"] == null)
                {
                    FormsAuthentication.SignOut();
                    httpContext.Response.Redirect("~/?returnurl=" + httpContext.Request.Url.ToString());
                    return false;
                }
            }
            return true;
        }
    }

Ich habe in einem anderen Thread gelesen, dass, wenn der Benutzer nicht authentifiziert ist und Sie eine Ajax-Anforderung stellen, Sie den Statuscode auf 401 (nicht autorisiert) setzen und danach in Js prüfen und sie auf die Anmeldeseite umleiten sollten. Ich kann das jedoch nicht zum Laufen bringen:

protected override void OnActionExecuting(ActionExecutingContext filterContext)
        {
            if (Request.IsAjaxRequest() && (!Request.IsAuthenticated || User == null))
            {
                filterContext.RequestContext.HttpContext.Response.StatusCode = 401;
            }
            else
            {
                base.OnActionExecuting(filterContext);
            }
        }

Im Grunde wird es auf 401 gesetzt, aber dann wird die Controller-Aktion fortgesetzt und ein Objekt ref ausgegeben, das nicht auf eine Instanz eines Objektfehlers gesetzt ist, die dann den Fehler 500 an die clientseitigen Js zurückgibt. Wenn ich mein benutzerdefiniertes Authorize-Attribut ändere, um auch ajax-Anforderungen zu überprüfen und bei nicht authentifizierten Werten false zurückzugeben, führt dies dazu, dass die ajax-Anforderung meine Anmeldeseite zurückgibt, was offensichtlich nicht funktioniert.

Wie bekomme ich das zum Laufen?

55
Justin

Sie könnten ein benutzerdefiniertes [Authorize]-Attribut schreiben, das JSON zurückgibt, anstatt bei nicht autorisiertem Zugriff eine 401-Ausnahme auszulösen, wodurch Clientscripts das Szenario ordnungsgemäß bearbeiten können:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class MyAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAjaxRequest())
        {
            filterContext.Result = new JsonResult
            {
                Data = new 
                { 
                    // put whatever data you want which will be sent
                    // to the client
                    message = "sorry, but you were logged out" 
                },
                JsonRequestBehavior = JsonRequestBehavior.AllowGet
            };
        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }
}

dekorieren Sie dann Ihre Controller/Aktionen damit und auf dem Client:

$.get('@Url.Action("SomeAction")', function (result) {
    if (result.message) {
        alert(result.message);
    } else {
        // do whatever you were doing before with the results
    }
});
83
Darin Dimitrov

Ich würde JsonRequestBehavior nicht in AllowGet ändern. Stattdessen schlage ich vor:

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public sealed class MyAuthorizeAttribute : AuthorizeAttribute
{
    public override void OnAuthorization(AuthorizationContext filterContext)
    {
        base.OnAuthorization(filterContext);
        OnAuthorizationHelp(filterContext);
    }

    internal void OnAuthorizationHelp(AuthorizationContext filterContext)
    {

        if (filterContext.Result is HttpUnauthorizedResult)
        {
            if (filterContext.HttpContext.Request.IsAjaxRequest())
            {
                filterContext.HttpContext.Response.StatusCode = 401;
                filterContext.HttpContext.Response.End();
            }
        }
    }
}

und fügen Sie einen globalen js ajax-Fehlerhandler hinzu:

   $(document).ajaxError(function (xhr, props) {
        if (props.status === 401) {
            location.reload(); 
        }
   }
37
free4ride

Auch wenn dies schon lange nicht mehr beantwortet wurde, denke ich, dass dies die kürzeste und süßeste Antwort ist, wenn Sie .NET 4.5 verwenden. Kleine Eigenschaft namens SuppressFormsAuthenticationRedirect, die hinzugefügt wurde. Setzen Sie diese Option auf "true", um die Seite "302 Umleitung zur Anmeldung" nicht auszuführen.

http://msdn.Microsoft.com/de-de/library/system.web.httpresponse.suppressformsauthenticationredirect.aspx

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AjaxAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        // returns a 401 already
        base.HandleUnauthorizedRequest(filterContext);
        if (filterContext.HttpContext.Request.IsAjaxRequest())
        {
            // we simply have to tell mvc not to redirect to login page
            filterContext.HttpContext.Response.SuppressFormsAuthenticationRedirect = true;
        }
    }
}

Angenommen, Sie planen, die Ajax-Anforderungen zu bearbeiten, schlagen einen Failback/Fehler-Rückruf vor, in dem Sie einen 401 Unauthorized erhalten.

8
Nicholi

Fügen Sie auf der Masterseite dieses Jquery-Skript hinzu ------------

<script type="text/javascript">

   $.ajaxSetup({
        statusCode: {
            403: function () {
                window.location.reload();
            }
        }
    });


    OR


    $.ajaxSetup({
        error: function (x, e) {
            if (x.status == 403) {
                window.location.reload(); 
            }
        }
    });

</script>

Fügen Sie eine cs-Datei mit dem Namen TraceFilter in Ihrem Projekt hinzu, und schreiben Sie eine seald-Klasse TraceFilterAttribute, die an ActionFilterAttribute erbt. Fügen Sie die TraceFilterAttribute-Klasse in FilterConfig.cs hinzu, die im Ordner App_Start Ihres Projekts verfügbar ist, indem Sie die folgende Zeile eingeben.

filters.Add (new TraceFilterAttribute ());

Überschreiben Sie die Methode OnActionExecuting () in der TraceFilterAttribute-Klasse. Dadurch wird die Sitzung automatisch geprüft. Wenn die Sitzung null gefunden wird, wird das auf der Masterseite verfügbare Skript aufgerufen. Von dort aus können Sie zu Ihrer Auswahlseite gehen.

[AttributeUsage(AttributeTargets.All)]
public sealed class TraceFilterAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
    {
        if (filterContext != null)
        {
HttpSessionStateBase objHttpSessionStateBase = filterContext.HttpContext.Session;
                var userSession = objHttpSessionStateBase["etenetID"];
if (((userSession == null) && (!objHttpSessionStateBase.IsNewSession)) || (objHttpSessionStateBase.IsNewSession))
                {
                    objHttpSessionStateBase.RemoveAll();
                    objHttpSessionStateBase.Clear();
                    objHttpSessionStateBase.Abandon();
                    if (filterContext.HttpContext.Request.IsAjaxRequest())
                    {
                        filterContext.HttpContext.Response.StatusCode = 403;
                        filterContext.Result = new JsonResult { Data = "LogOut" };
                    }
                    else
                    {
                        filterContext.Result = new RedirectResult("~/Admin/GoToLogin");
                    }

                }


}
}

}
5
Shoeb

Ich hatte ein ähnliches Problem und fand this

Erzwingen Sie ASP.NET, einen 401-Code zurückzugeben, anstatt JSON direkt vor dem Zurücksenden der Antwort zurückzugeben. In Global.asax:

protected void Application_EndRequest()
    {
        var context = new HttpContextWrapper(Context);
        if (context.Request.IsAjaxRequest() && context.Response.StatusCode == 302)
        {
            Context.Response.Clear();
            Context.Response.Write("**custom error message**");
            Context.Response.StatusCode = 401;
        }
    }

Dann können Sie den Client in JavaScript/jQuery oder was auch immer Sie verwenden, damit umgehen lassen

4
ShaneA

so gehe ich in meiner benutzerdefinierten Autorisierung auf so einfache Weise vor. Ich überprüfe, ob die Sitzung beendet ist, und handele dies als nicht autorisiert mit einem Boolean, um zu prüfen, ob die Authentifizierung wirklich authentifiziert ist, aber nicht autorisiert ist (zur nicht autorisierten Seite umleiten). oder es wird aufgrund von Sitzungszeitüberschreitung nicht authentifiziert (Weiterleitung zum Login) 

 private bool ispha_LoggedIn = false;
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        ispha_LoggedIn = false;
        var session = httpContext.Session;
        bool authorize = false;
        if (httpContext.Session["authenticationInfo"] == null)
        {

            return authorize;
        }

        using (OrchtechHR_MVCEntities db = new OrchtechHR_MVCEntities())
        {
            UserAuthenticationController UM = new UserAuthenticationController();
            foreach (var roles in userAssignedRoles)
            {
                authorize = UM.IsUserInRole(httpContext.User.Identity.Name, roles);

                if (authorize)
                {

                    return authorize;
                }

            }
        }
        ispha_LoggedIn = true;
        return authorize;
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (ispha_LoggedIn==false)
        {
            filterContext.Result = new RedirectResult("~/UserAuthentication/LogIn");
        }
        else
        {
            filterContext.Result = new RedirectResult("~/Dashboard/UnAuthorized");
        }


    }

Hoffen Sie, wenn dies jemanden führt, und bitte, wenn es Kommentare gibt, ist es dennoch willkommen, sie zu kennen.

1
IsPha

Möglicherweise möchten Sie versuchen, HttpException auszulösen und in Ihrem Javascript einzufangen.

throw new HttpException(401, "Auth Failed")
0
Dimitri