ASP.NET Identity WebApi 2 vs MVC 5登录Cookies

时间:2015-01-24 22:48:27

标签: c# asp.net asp.net-mvc asp.net-web-api asp.net-identity

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

对于身份验证,我使用默认为新的ASP.NET MVC项目提供的ASP.NET Identity库。

我得到了一切正常,使用MVC 5一切都很好。但对于我的生活,我无法让标准MVC控制器返回简单的JSON。 (它包装了我想要在父对象中返回的JSON)是的,我可以在客户端修复此问题,但对我来说这是hacky。

我的另一个看起来更好的选择是使用WebApi,它按照我的期望返回对象(只是我的JSON作为正文)。但我遇到的问题是ASP.NET身份SignInManager没有发送.ASPNet.Identity cookie,除非我返回一个ActionResult。

以下是我的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可能正在将cookie分配给之前生成的HttpContext.Current.Response对象。当我返回一个JsonResult时,ASP.NET将此结果固定到HttpContext.Current.Response并发送到客户端,因此具有cookie。

但是当我返回一个HttpResponseMessage时,ASP.NET返回新创建的HttpResponse,它没有SignInManager cookie。我是否认为这是正确的?

编辑1:正如@David Tansey所建议我尝试了以下操作,但仍然没有设置cookie但返回正确的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,但没有cookie:

{"status":"Success"}

FIX:在@David Tansey指出使用匿名类型new {}之后,我决定尝试一下。以下两种方法可以正常工作

MVC

必须返回一个ActionResult / JsonResult,除Data之外的所有字段都为null,并且必须返回Anonymous类型而不是动态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

必须将返回类型更改为object,将其序列化为Json,并设置cookie。返回HttpResponseMessage导致SignInManager设置为丢失的cookie我猜它是使用新返回的响应对象的开始。

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

2 个答案:

答案 0 :(得分:1)

也许您已将AuthenticationMode设置为Passive。尝试将此更改为“活动”。

来源 http://brockallen.com/2013/10/27/host-authentication-and-web-api-with-owin-and-active-vs-passive-authentication-middleware/

答案 1 :(得分:0)

也许问题可能是你试图使用cookie,而你应该使用令牌......这就是你遇到hackyness问题的原因。

请参阅本指南,了解如何设置基于令牌的身份验证:http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/

(通常我会发布相关的代码,但是有很多内容可以用来设置它。)