1

我正在使用 MVC 4 构建一个单页应用程序。对于登录功能,我对此操作执行 jquery ajax POST:

    [HttpPost] [AllowAnonymous]
    public JsonResult JsonLogin(LogInFormViewModel form)
    {
         ...

         //If user authenticates
            formAuthentication.SetAuthCookie(this.HttpContext,
                                                 UserAuthenticationTicketBuilder.CreateAuthenticationTicket(
                                                                 user));
            return Json(new { success = true, viewResult = this.RenderPartialView("UserStatusBar", null) });

         ...

    }

RenderPartialView()是一个自定义扩展,它只是将我的剃刀部分视图呈现为字符串。

“UserStatusBar”是任何网站顶部的标准栏,如果用户未通过身份验证,则显示登录/注册,如果用户未通过身份验证,则显示注销/欢迎:

@if (Request.IsAuthenticated)
{
    <div id="LoggedIn">
        <a class="logoutLink" href="#">Log out</a>
        <span>Welcome, @User.Identity.Name</span>
    </div>
} else {
    <div id="notLoggedIn">
        <a class="loginLink popupLink" href="#">Log in</a>
        <a class="registerLink popupLink" href="#">Register</a>
    </div>
}

在我的 ajax 成功处理程序中,我做了这样的事情来在用户登录或注销后异步重新呈现用户状态栏:

success: function (result) {
    if (result.success) {
       $('#userStatusBar').empty().html(result.viewResult, null);
    }
}

唯一的问题是,每当代码进入我的自定义扩展RenderPartialView()时,Request.IsAuthenticated它仍然与 ajax 调用之前相同,因此在下一个请求之前它不会重新呈现正确的状态栏。

我该如何解决这个问题,因为Request.IsAuthenticated它是只读的,我不能在设置授权 cookie 后简单地设置它。我唯一能做的就是设置一个 TempData 属性并在渲染 UserStatusBar 时检查它:

@if (Request.IsAuthenticated || (TempData["AjaxAuthenticated"] != null && (bool)TempData["AjaxAuthenticated"]))
{
    <logged in html>
} else <logged out html>

但这是有问题的,因为注销时会发生相反的情况;在重新渲染状态栏并且它再次为状态栏渲染不正确的标记直到下一个请求Request.IsAuthenticated之后仍然为真。formsAuthentication.SignOut()

我似乎想不出解决这个问题的方法,因为我还需要永久链接才能工作,所以 Request.IsAuthenticated 是我在这种情况下要查看的那个。

4

1 回答 1

1

好的,我找到了答案。我编写了一个控制器扩展,它根据当前响应中的 cookie 更新当前请求的安全主体(在成功授权之后和调用此方法之前设置)。这会立即更新Request.IsAuthenticatedtrue。

注意:我正在使用自定义成员资格,因此此代码对您不适用。

    public static void AjaxRenewPrincipal(this Controller controller)
    {
        HttpCookie authCookie = controller.HttpContext.Response.Cookies[FormsAuthentication.FormsCookieName];
        if (IsValidAuthCookie(authCookie))
        {
            var formsAuthentication = DependencyResolver.Current.GetService<IFormsAuthentication>();
            var authTicket = formsAuthentication.Decrypt(authCookie.Value);

            CustomUser user = new CustomUser(authTicket); //An authenticated user
            string[] userRoles = { user.RoleName };
            controller.HttpContext.User = new GenericPrincipal(user , userRoles);
            formsAuthentication.SetAuthCookie(controller.HttpContext, authTicket);
        }
        else
        {
            //using Parameter-less constructor on my CustomClass : IIdentity sets IsAuthenticated to false on the IIdentity, then unauthenticated user gets set to the security principal
            controller.HttpContext.User = new GenericPrincipal(new CustomUser (), new string[] {});
        }
    }
于 2012-12-18T09:41:38.367 回答