ASP.NET Identity WebApi 2 vs MVC 5 Login

I am using ASP.NET MVC 5 and WebApi 2 and trying to do Ajax login with redirect if successful.

For authentication, I use ASP.NET identity libraries, which by default appear for a new ASP.NET MVC project.

Everything worked for me, and everything was fine with MVC 5. But for life, I cannot get the standard MVC to return just plain JSON. (It wraps my JSON, which I want to return in the parent object) yes, I could fix it on the client side, but this is hacky for me.

Another option that seems better is to use WebApi, which returns objects as I expect them (just my JSON as a body). But the problem I am facing is that ASP.NET Identity SignInManager does not send .ASPNet.Identity cookies unless I return ActionResult.

Below is my WebApi controller, which returns the correct expected minimum JSON, but does not send Set-Cookie commands, so any redirection sees the user as not registered.

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

which returns the following Json but not cookies:

 {"status":"Success"} 

If I change this to return an ActionResult rather than an HttpResponseMessage, Set-Cookie commands are sent, but Json is wrapped inside additional properties.

  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}; } 

Which returns cookies, but wrapped by Json:

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

Now I assume it happens because SignInManager probably assigns cookies to the HttpContext.Current.Response object that was generated earlier. And when I return JsonResult, ASP.NET pulls this result to HttpContext.Current.Response and sends it to the client, so it has cookies.

But when I return the HttpResponseMessage, ASP.NET returns the newly created HttpResponse, which does not have a SignInManager cookie. Am I correct in this?

EDIT 1: As @David Tansey suggested, I tried the following, which still does not set cookies, but returns the correct 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()}); } 

Returns the correct json but not cookies:

 {"status":"Success"} 

FIX: After @David Tansey pointed out using the anonymous type new {}, I decided to try it. And the following two methods work

MVC

had to return an ActionResult / JsonResult for which all fields except Data were empty and had to return the Anonymous type, and not the dynamic ExpandoObject() , since the dynamic object caused the serialization of the returned Json to multiply

  [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

It is required to change the type of the returned object to an object that is serialized in Json, and also sets cookies. The return of the HttpResponseMessage causes the cookies that the SignInManager sets to lose, I assume that its beginning uses the newly returned response object.

  [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()}; } 
+6
source share
2 answers

You may have set AuthenticationMode as passive. Try changing this to Active.

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

+1
source

Perhaps the problem may be that you are trying to use cookies when you should use tokens instead ... and that is why you are faced with a hacking problem.

See this guide to learn how to configure token-based authentication: http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net -identity /

(Normally, I would post the appropriate code, but there are quite a lot in the configuration.)

0
source

Source: https://habr.com/ru/post/981500/


All Articles