我正在使用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()};
}
答案 0 :(得分:1)
也许您已将AuthenticationMode设置为Passive。尝试将此更改为“活动”。
答案 1 :(得分:0)
也许问题可能是你试图使用cookie,而你应该使用令牌......这就是你遇到hackyness问题的原因。
请参阅本指南,了解如何设置基于令牌的身份验证:http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/
(通常我会发布相关的代码,但是有很多内容可以用来设置它。)