Обработка тайм-аута сеанса в вызовах ajax - PullRequest
56 голосов
/ 09 марта 2011

Я делаю вызов ajax с использованием jquery для действия контроллера asp.net mvc:

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

Когда время сеанса истечет, этот вызов не будет выполнен, так как объект User сохраняется в сеансе. Я создал собственный атрибут авторизации, чтобы проверить, был ли сеанс потерян, и перенаправить на страницу входа. Это прекрасно работает для запросов страниц, однако не работает для запросов ajax, так как вы не можете перенаправить запрос 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;
        }
    }

Я прочитал в другой ветке, что, когда пользователь не аутентифицирован, и вы делаете запрос ajax, вы должны установить код состояния 401 (не авторизован), а затем проверить это в js и перенаправить их на страницу входа. Однако я не могу заставить это работать:

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

По сути, он установит его на 401, но затем продолжит работу контроллера и выдаст объект ref, не установленный в качестве экземпляра ошибки объекта, который затем вернет ошибку 500 обратно на js на стороне клиента. , Если я изменю свой собственный атрибут Authorize, чтобы также проверять запросы ajax и возвращал false для тех, кто не прошел проверку подлинности, то запрос ajax возвращает мою страницу входа, что, очевидно, не работает.

Как мне заставить это работать?

Ответы [ 8 ]

84 голосов
/ 09 марта 2011

Вы можете написать собственный атрибут [Authorize], который будет возвращать JSON вместо исключения 401 в случае неавторизованного доступа, который позволит клиентским сценариям корректно обрабатывать сценарий:

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

и затем украшатьконтроллер / действия с ним и на клиенте:

$.get('@Url.Action("SomeAction")', function (result) {
    if (result.message) {
        alert(result.message);
    } else {
        // do whatever you were doing before with the results
    }
});
37 голосов
/ 03 июня 2012

Я бы не стал изменять JsonRequestBehavior на AllowGet. Вместо этого я предлагаю:

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

и добавьте глобальный обработчик ошибок js ajax:

   $(document).ajaxError(function (xhr, props) {
        if (props.status === 401) {
            location.reload(); 
        }
   }
8 голосов
/ 11 мая 2013

Несмотря на то, что это ответ на прошлый вопрос, я думаю, что это самый короткий и сладкий ответ, если вы используете .NET 4.5.Небольшое свойство под названием SuppressFormsAuthenticationRedirect, которое было добавлено.Установите значение true, и оно не будет выполнять страницу 302 Redirect для входа в систему.

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

Предполагается, что вы планируете обрабатывать вызовы ajax с ошибками / обратными вызовами, в которых вы будете выполнятьполучить 401 Несанкционированный.

5 голосов
/ 01 июля 2013

На главной странице добавьте этот скрипт 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>

Добавьте файл cs с именем TraceFilter в свой проект и напишите класс печати TraceFilterAttribute, унаследованный для ActionFilterAttribute. Добавьте класс TraceFilterAttribute в FilterConfig.cs, доступный в папке App_Start вашего проекта, написав строку ниже.

filters.Add (new TraceFilterAttribute ());

Переопределить метод OnActionExecuting () в классе TraceFilterAttribute. Это автоматически проверит сессию, и если сессия найдет ноль, то вызовет скрипт, доступный на главной странице, и из их можно перейти на страницу выбора.

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

                }


}
}

}
4 голосов
/ 15 декабря 2012

У меня была похожая проблема, и я обнаружил this

Вместо того, чтобы возвращать какой-либо JSON, непосредственно перед отправкой ответа, принудительно заставить ASP.NET вернуть код 401.В 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;
        }
    }

Затем вы можете позволить клиенту справиться с этим в JavaScript / jQuery или в любом другом используемом вами

1 голос
/ 07 мая 2016

вот как я так легко справляюсь в своей пользовательской авторизации, я проверяю, не завершился ли сеанс, и обрабатываю это как неавторизованный с логическим значением, чтобы проверить, действительно ли он аутентифицирован, но не авторизован (для перенаправления на авторизованная страница) или она не аутентифицирована из-за истечения времени сеанса (перенаправление на страницу входа)

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


    }

Надеюсь, если этим кто-то руководствуется, и, пожалуйста, если есть комментарии, желательно знать их.

0 голосов
/ 31 марта 2016

при вызове ajax, если сеанс истек, возвращает что-то вроде этого

<script>
$(function(){
    location.reload();
});
</script>

хаха ...

0 голосов
/ 09 марта 2011

Возможно, вы захотите сгенерировать HttpException и поймать его в своем JavaScript.

throw new HttpException(401, "Auth Failed")
...