56 votes

La manipulation d'expiration de la session dans les appels ajax

Je suis en train de faire un appel ajax à l'aide de jquery pour un asp.net mvc action de contrôleur:

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

Lors de la session d', cet appel échoue, l'objet Utilisateur est stocké dans la session. J'ai créé un custom autoriser attribut afin de vérifier si la session a été perdu et les rediriger vers la page de connexion. Cela fonctionne très bien pour les demandes de page, cependant, il ne fonctionne pas pour les requêtes ajax, que vous ne pouvez pas rediriger une requête ajax:

[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;
        }
    }

J'ai lu sur un autre thread que lorsque l'utilisateur n'est pas authentifié et vous faire une requête ajax, vous devez définir le code d'état à 401 (non autorisé) et vérifier alors qu'en js et les rediriger vers la page de connexion. Cependant, je ne peux pas le faire fonctionner:

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

En gros, c'vais le mettre à 401, mais alors il va continuer dans le contrôleur de l'action et de jeter un objet ref n'est pas définie à une instance d'un objet d'erreur, puis renvoie une erreur 500 du côté client js. Si je change mon custom Autoriser attribut pour valider les requêtes ajax ainsi et renvoie la valeur false pour ceux qui ne sont pas authentifiés, qui fait la requête ajax retour de ma page de connexion, ce qui évidemment ne fonctionne pas.

Comment puis-je le faire fonctionner?

85voto

Darin Dimitrov Points 528142

Vous pourriez écrire une coutume [Authorize] attribut qui permettrait le retour JSON au lieu de lancer 401 exception en cas d'accès non autorisé qui permettrait au client de scripts pour gérer le scénario gracieusement:

[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);
        }
    }
}

ensuite, décorez votre contrôleur/actions avec et pour le client:

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

37voto

free4ride Points 566

Je ne changerai pas JsonRequestBehavior à AllowGet. Au lieu de cela, je suggère:

[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();
            }
        }
    }
}

et d'ajouter mondiale js ajax gestionnaire d'erreurs:

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

8voto

Nicholi Points 425

Même si cela s'est bien passé, a répondu, je pense que c'est le plus court et le plus doux de répondre si vous êtes en utilisant .NET 4.5. Peu de propriété appelée SuppressFormsAuthenticationRedirect qui a été ajouté. La valeur true et il ne sera pas effectuer la Redirection 302 vers la page de connexion.

http://msdn.microsoft.com/en-us/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;
        }
    }
}

En supposant que vous prévoyez sur l'utilisation des requêtes ajax échec ou l'erreur de rappel, dans lequel vous obtiendrez un 401 non autorisé.

6voto

Shoeb Points 254

Sur la page principale ajouter ce script jquery ------------

<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>

Ajouter une cs fichier nommé avec filtre tracefilter dans votre projet et de rédiger un seald classe TraceFilterAttribute hériter de ActionFilterAttribute. Ajouter TraceFilterAttribute classe dans FilterConfig.cs disponible dans App_Start dossier de votre projet par écrit en dessous de la ligne.

les filtres.Add(new TraceFilterAttribute());

Remplacer la méthode OnActionExecuting() dans TraceFilterAttribute classe. Cela va automatiquement vérifier la session et si trouve session null alors des appels de script disponible dans la page maître et de de leur, vous pouvez aller à votre page de choix.

[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");
                    }

                }


}
}

}

4voto

ShaneA Points 378

J'ai eu un problème similaire et a trouvé cette

Au lieu de retourner tout JSON, juste avant que la réponse est renvoyée, de la force ASP.NET pour revenir un 401 du code. En 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;
        }
    }

Ensuite, vous pouvez laisser le client de traiter avec elle en JavaScript/jQuery ou ce que vous utilisez

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X