【问题标题】:Handling session timeout with Ajax in .NET Core MVC在 .NET Core MVC 中使用 Ajax 处理会话超时
【发布时间】:2019-08-16 02:23:19
【问题描述】:

我有一个使用基于 cookie 的身份验证的常规应用程序。这是它的配置方式:

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication("Login")
            .AddCookie("Login", c => {
                c.ClaimsIssuer = "Myself";
                c.LoginPath = new PathString("/Home/Login");
                c.AccessDeniedPath = new PathString("/Home/Denied");
            }); 
}

这适用于我的常规操作:

[Authorize]
public IActionResult Users()
{
    return View();
}       

但不适用于我的 ajax 请求:

[Authorize, HttpPost("Api/UpdateUserInfo"), ValidateAntiForgeryToken, Produces("application/json")]
public IActionResult UpdateUserInfo([FromBody] Request<User> request)
{
    Response<User> response = request.DoWhatYouNeed();

    return Json(response);
}

问题是,当会话过期时,MVC 引擎会将操作重定向到登录页面,而我的 ajax 调用将收到该操作。 我希望它返回 401 的状态代码,这样当它是一个 ajax 请求时,我可以将用户重定向回登录页面。 我尝试编写策略,但不知道如何取消设置或使其忽略从身份验证服务到登录页面的默认重定向。

public class AuthorizeAjax : AuthorizationHandler<AuthorizeAjax>, IAuthorizationRequirement
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, AuthorizeAjax requirement)
    {
        if (context.User.Identity.IsAuthenticated)
        {
            context.Succeed(requirement);
        }
        else
        {   
            context.Fail();
            if (context.Resource is AuthorizationFilterContext redirectContext)
            {
                // - This is null already, and the redirect to login will still happen after this.
                redirectContext.Result = null;
            }
        }

        return Task.CompletedTask;
    }
}

我该怎么做?

编辑:经过大量谷歌搜索,我在 2.0 版中发现了这种处理它的新方法:

services.AddAuthentication("Login")
        .AddCookie("Login", c => {
                   c.ClaimsIssuer = "Myself";
                   c.LoginPath = new PathString("/Home/Login");
                   c.Events.OnRedirectToLogin = (context) =>
                   {
                       // - Or a better way to detect it's an ajax request
                       if (context.Request.Headers["Content-Type"] == "application/json")
                       {
                           context.HttpContext.Response.StatusCode = 401;
                       }
                       else
                       {
                           context.Response.Redirect(context.RedirectUri);
                       }

                       return Task.CompletedTask;
                   };                       
        });

它现在有效!

【问题讨论】:

  • 调用 ajax 请求时发生了什么?你得到 401 还是得到其他异常?
  • 检查this 答案。它不适用于核心,但我认为它应该可以工作。
  • @ManojChoudhari 我没有收到任何错误,而是获得了登录页面的 HMTL 代码。
  • 我对 AzureAD 有同样的问题,并根据您的回答解决了它 - 请参阅 github.com/aspnet/AspNetCore/issues/7348 - 我修改了 AzureAdAuthenticationBuilderExtensions.cs 2 个不同之处:1)更改 OnRedirectToIdentityProvider 和 2)您需要调用上下文。处理响应();以便将状态码传播给用户。

标签: c# ajax .net-core asp.net-core-mvc


【解决方案1】:

你需要的可以通过扩展 AuthorizeAttribute 类来实现。

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class AjaxAuthorizeAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAjaxRequest())
        {
             filterContext.HttpContext.Response.StatusCode = 401;
             filterContext.Result = new JsonResult
             {
                 Data = new { Success = false, Data = "Unauthorized" },
                 ContentEncoding = System.Text.Encoding.UTF8,
                 ContentType = "application/json",
                 JsonRequestBehavior = JsonRequestBehavior.AllowGet
             };
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }
}

然后您可以在 Ajax 方法上指定此属性。

希望这会有所帮助。

参考:http://benedict-chan.github.io/blog/2014/02/11/asp-dot-net-mvc-how-to-handle-unauthorized-response-in-json-for-your-api/

【讨论】:

  • 我刚刚从您的其他评论中尝试过这个,但不幸的是它不起作用。 .Net Core 的 MVC 登录服务似乎覆盖了之前的任何内容,它将所有 401(以及其他一些响应)变为它的配置值或默认值。我使用其他响应代码进行了测试,但登录服务似乎将其他所有内容重定向到它的DeniedPath,即使它没有设置。似乎它是专门为在所有方面都是反 ajax 的......
  • 您是否将自定义授权属性应用于操作?当时控制器上有授权属性吗?如果在那个 cas 中是,您可以在控制器级别应用自定义授权属性并再次检查。
  • 查看我上面的评论:stackoverflow.com/questions/55344665/… 我需要调用 context.HandleResponse();在我的情况下解决您的问题。
猜你喜欢
  • 2012-11-10
  • 1970-01-01
  • 2017-10-06
  • 1970-01-01
  • 2014-03-22
  • 2017-12-30
  • 2011-07-11
  • 2016-03-27
相关资源
最近更新 更多