ASP.NET Identity WebApi 2和MVC 5登录cookies的比较

7

我正在使用ASP.NET MVC 5和WebApi 2,尝试进行Ajax登录并在成功后重定向。

为了进行身份验证,我正在使用默认情况下为新ASP.NET MVC项目提供的ASP.NET Identity库。

我已经让所有东西都运作良好,并且在使用MVC 5时一切正常。但是,我无论如何都无法使标准的MVC控制器仅返回简单的JSON。(它会将我要返回的JSON包装在一个父对象中)。是的,我可以在客户端上解决这个问题,但对我来说这是一个hacky的方法。

我的另一个选择似乎更好,那就是使用WebApi,它将对象返回为我期望的形式(只是我的JSON作为正文)。但我遇到的问题是,除非我返回一个ActionResult,否则ASP.NET Identity SignInManager不会发送.ASPNet.Identity cookie。

以下是我的WebApi控制器,它返回了正确预期的最小JSON,但没有发送Set-Cookie命令,因此任何重定向都会将用户视为未登录。

[Authorize]
public class AccountController : ApiController
{
    public AccountController(IApplicationSignInManager signInManager)
    {
        SignInManager = signInManager;
    }

    public IApplicationSignInManager SignInManager {....}

    //
    // POST: /Account/Login
    [HttpPost]
    [AllowAnonymous]
    [NgValidateAntiForgeryToken]
    public async Task<HttpResponseMessage> Login(LoginViewModel model)
    {
        // Temporarily using Dynamic 
        dynamic res = new ExpandoObject();

        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, change to shouldLockout: true
        var status = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);

        res.status = status.ToString();

        return new HttpResponseMessage(HttpStatusCode.OK)
        {
            Content = new StringContent(Newtonsoft.Json.JsonConvert.SerializeObject(res))
        };
    }
}

该方法返回以下Json但不返回cookie:

{"status":"Success"}

如果我把这个改成返回ActionResult而不是HttpResponseMessage,那么Set-Cookie命令会被发送,但是Json会被包裹在额外的属性中。
    public async Task<ActionResult> Login(LoginViewModel model)
    {
        // Temporarily using Dynamic 
        dynamic res = new ExpandoObject();

        // This doesn't count login failures towards account lockout
        // To enable password failures to trigger account lockout, change to shouldLockout: true
        var status = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);

        res.status = status.ToString();

        return new JsonResult{Data = res};
    }

这个返回cookie,但是被Json包装了:

 {"contentEncoding":null,"contentType":null,"data":{"status":"Success"},"jsonRequestBehavior":1,"maxJsonLength":null,"recursionLimit":null}

现在我猜测这是因为SignInManager可能会将cookies分配给先前生成的HttpContext.Current.Response对象。当我返回JsonResult时,ASP.NET将此结果附加到HttpContext.Current.Response并发送到客户端,因此具有cookies。
但是,当我返回HttpResponseMessage时,ASP.NET返回新创建的HttpResponse,其中没有SignInManager cookies。我想这样想是正确的吗?
编辑1:根据@David Tansey的建议,我尝试了以下操作,仍未设置cookies,但返回正确的Json。
    public async Task<IHttpActionResult> Login(LoginViewModel model)
    {            
        var status = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);

        return Json(new {status = status.ToString()});
    }

返回正确的JSON,但没有cookies:

{"status":"Success"}

修复:在@David Tansey指出使用匿名类型new {}之后,我决定尝试一下。以下两种方法都有效。

MVC

必须返回一个ActionResult/JsonResult,其中除了Data之外的所有字段都为null,并且必须返回一个匿名类型,而不是动态的ExpandoObject(),因为动态对象会导致序列化程序使返回的Json膨胀。

    [HttpPost]
    [AllowAnonymous]
    [NgValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel model)
    {
        var status = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);

        //return Json(new {status = status.ToString()});
        // OR
        return new JsonResult { Data = new { status = status.ToString() } };
    }

WebApi 2

必须将返回类型更改为对象,该对象会被序列化为Json并设置cookies。如果返回HttpResponseMessage,则由SignInManager设置的cookies似乎会丢失,因为它开始使用新返回的响应对象。

    [HttpPost]
    [AllowAnonymous]
    [NgValidateAntiForgeryToken]
    public async Task<object> Login(LoginViewModel model)
    {
        var status = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);

        return new {status = status.ToString()};
    }

我不确定你在询问什么。能否请你重新表述你的问题? - trailmax
@DavidTansey请看Edit 1,返回正确的Json,但仍无法获取cookies :-( - Michal Ciechan
我现在也在看同样的MSDN文档,而且我也在问自己同样的问题。非常有趣。 - David Tansey
虽然有点晦涩,但这实际上很有帮助。谢谢! - JacobE
很高兴能帮到你,对于密码学方面的问题感到抱歉! - Michal Ciechan
显示剩余9条评论
2个回答

1

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接