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

Mic*_*han 6 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标识库.

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

我似乎更好的另一个选择是使用WebApi,它按照我的期望返回对象(只是我的JSON作为正文).但我遇到的问题是ASP.NET身份SignInManager不发送.ASPNet.Identitycookie,除非我返回一个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))
        };
    }
}
Run Code Online (Sandbox Code Playgroud)

返回以下Json但没有cookie:

{"status":"Success"}
Run Code Online (Sandbox Code Playgroud)

如果我将其更改为返回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};
    }
Run Code Online (Sandbox Code Playgroud)

哪个返回cookie但包裹了Json:

 {"contentEncoding":null,"contentType":null,"data":{"status":"Success"},"jsonRequestBehavior":1,"maxJsonLength":null,"recursionLimit":null}
Run Code Online (Sandbox Code Playgroud)

现在我猜他正在发生,因为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()});
    }
Run Code Online (Sandbox Code Playgroud)

返回正确的json,但没有cookie:

{"status":"Success"}
Run Code Online (Sandbox Code Playgroud)

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() } };
    }
Run Code Online (Sandbox Code Playgroud)

WebApi 2

不得不将返回类型更改为对象,将其序列化为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()};
    }
Run Code Online (Sandbox Code Playgroud)

Ser*_*gan 0

也许问题在于您正在尝试使用 cookie,而您应该使用令牌……这就是您遇到 hackyness 问题的原因。

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

(通常我会发布相关代码,但设置它需要相当多的内容。)