User.Identity.GetUserId() returns null after successful login
Solution 1
Actually, the user is not signed in - not in the context of the current request (the POST /Account/Login
request), which is where User.Identity
gets its data. If you want to extract the id of the user currently trying to (and apparently succeeding) to sign in, you need to do that in some other way, like hijacking some step inside the call to SignInManager.PasswordSignInAsync
. If you are implementing your own MembershipProvider
, this should be easy.
Otherwise, you will have to wait for the next request (any request handled by some Controller's Action method should do fine) to use User.Identity
in the way you want to.
Some added explanation
When your Login
method gets called, the request context is already evaluated and a lot of data is available. For example HTTP headers, cookies and so on. This is where all the context information is found, like User.Identity
.
When you call SignInManager.PasswordSignInAsync(...)
, this does not affect the values of the request context, because this would make no sense – since the browser has not changed its mind about what it sent a few milliseconds ago. What it does affect is the response context to add a cookie containing some user and session id. This cookie is then sent to the browser, which then sends it back to server for each successive request. So all requests later than this one (until the user signs out or the cookie gets too old) will include information for the User.Identity
to interpret.
Solution 2
Simply try this :
string userId = SignInManager
.AuthenticationManager
.AuthenticationResponseGrant.Identity.GetUserId();
Solution 3
You could, in your case use other data to find the user that just logged in. Since we know that the login is successful and username is unique the following will work;
//
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
{
return Json(new { success = false, ex = "Fail to login." });
}
var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, isPersistent: true, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
string userId = UserManager.FindByName(model.Email)?.Id;
return Json(new { success = true });
case SignInStatus.Failure:
return Json(new { success = false, ex = "Email or password was incorrect." });
default:
return Json(new { success = false, ex = "Fail to login." });
}
}
Solution 4
HttpContext.User = await _signInManager.CreateUserPrincipalAsync(user);
After signing in you can use the sign in manager to create the user principal and manually assign the HttpContext.User reference
This will then allow you to access the user id like you would with a normal signed in page
var userId = userManager.GetUserId(HttpContext.User);
Solution 5
Yes, as Anders said, User.Identity and User.IsInRole will not work inside the same login action. So, You need to redirect to a new action, So inside login action add :
return RedirectToAction("MyNewLoginRoute", new {returnUrl=returnUrl });
below is a code example:
var result = SignInManager.PasswordSignIn(model.Email, model.Password, model.RememberMe, shouldLockout: false);
switch (result)
{
case SignInStatus.Success:
// below is the new line modification
return RedirectToAction("LoginRoute", new {returnUrl=returnUrl });
And Now add a new action LoginRoute as below :
// below method is new to get the UserId and Role
public ActionResult LoginRoute(string returnUrl) //this method is new
{
if (String.IsNullOrWhiteSpace(returnUrl))
{
if (User.IsInRole("Admin"))
{
return RedirectToLocal("/Admin");
}
else if (User.IsInRole("Partner"))
{
return RedirectToLocal("/Partner/Index/");
}
else if (User.IsInRole("EndUser"))
{
ApplicationDbContext db = new ApplicationDbContext();
// know the partner
int partnerID = db.Users.Where(x => x.UserName == User.Identity.Name).FirstOrDefault().PartnersTBLID;
return RedirectToLocal("/Partner/List/" + partnerID.ToString());
}
}
else
{
return RedirectToLocal(returnUrl);
}
}
Hope this could help someone.
Related videos on Youtube
Tân
Facebook group: Programming - Tips and tricks - Join to get and share your experience about programming
Updated on July 09, 2022Comments
-
Tân almost 2 years
I've defined a temp variable to get current user id, it always returns null.
Here is the snapshot:
Why?
UPDATE:
// // POST: /Account/Login [HttpPost] [AllowAnonymous] public async Task<ActionResult> Login(LoginViewModel model, string returnUrl) { if (!ModelState.IsValid) { return Json(new { success = false, ex = "Fail to login." }); } var result = await SignInManager.PasswordSignInAsync(model.Email, model.Password, isPersistent: true, shouldLockout: false); switch (result) { case SignInStatus.Success: string userId = User.Identity.GetUserId(); return Json(new { success = true }); case SignInStatus.Failure: return Json(new { success = false, ex = "Email or password was incorrect." }); default: return Json(new { success = false, ex = "Fail to login." }); } }
UPDATE 2:
On client side, I use ajax to connect to
/Account/Login
:var loginAjax = function (email, password, callback) { $.ajax({ url: '/Account/Login', type: 'POST', data: { Email: email, Password: password }, success: function (data) { $('body').css('cursor', 'default'); if (data.success) { callback(true) } else { $('#login-error').text(data.ex) } }, error: function () { $('#login-error').text('Không thể kết nối đến máy chủ.') } }); callback(false) }; // I've got email and password in another function to check valid or not loginAjax(email, password, function (success) { $('body').css('cursor', 'default'); switch (success) { case true: signin(function () { $('.login').html(''); window.location.href = '/?type=Promotion'; }); break case false: $('#Email-active').hide(); $('#Password-active').hide(); $('#Password').val(''); $('#login-btn').removeClass('disabled').attr('onclick', '$(this).addClass("disabled").removeAttr("onclick"); running()'); break } });
SignalR on client side:
var signalR = $.connection.chat; var signin = function (callback) { $.connection.hub.start().done(function () { signalR.server.signinToSignalR(); callback() }) };
SignalR on server side:
public void SigninToSignalR() { // this's always null string userId = HttpContext.Current.User.Identity.GetUserId(); }
-
Soner Gönül over 8 yearsPlease show your code as a text, not as an image.
-
-
Tân over 8 yearsThanks! Can you explain to me more about
the current request
andthe next request
? When is a request calledcurrent request
ornext request
? -
Anders Marzi Tornblad over 8 yearsWell, that's just basic English and temporality. The "current" request is the HTTP request that your code is currently handling - in this case it's the
POST /Account/Login
request. By the "next" request I simply mean the next request to come in at some later point in time (ranging from microseconds later to days later)... -
Tân over 8 yearsya. I think something maybe wrong. I'll give you an example: On client side, I use ajax to connect to
/Account/Login
. After successfull login, I use ajax again to connecet to signalR hub (/Hubs/ChatHub.cs
). I defined a method to get userId, but it's still null.public void SigninToSignalR() { string userId = HttpContext.Current.User.Identity.GetUserId(); }
-
Tân over 8 yearsThen, I've tried to get userId in the View:
@{ string userId = User.Identity.GetUserId(); }
. It's still null after refreshing the page. -
Anders Marzi Tornblad over 8 yearsFor the SignalR case, this can be tricky. There is an answer here that might help: stackoverflow.com/questions/22002092/…
-
Anders Marzi Tornblad over 8 yearsHave you implemented your own
MembershipProvider
? In that case, what have you done with regards toUserId
? I think the problem must be somewhere else. It looks like you are letting the user log in using an ajax request. Why? And what are you doing with the results on the client side? I think you need to update your question a bit. -
Tân over 8 yearsOh. Sorry. I've solved it by double refreshing page. I don't know why but
User.Identity.GetUserId()
has been working after I do that. :) -
Charleh over 7 yearsThis is the same reason why you need to do a redirect after logging out; logging out happens after the HTTP context has been constructed and if you issue a logout only the next request will actually be in a logged out context.
-
johnterkl87 about 6 yearsI like this response since it ties in nicely with already having the user object in many cases.
-
FindOutIslamNow over 5 yearsThis is the best answer for this question
-
eduardogoncalves over 5 yearsThank you! Worked like a charm!
-
Pat James over 4 yearsNice to get a solution rather than a long-winded explanation with very little actionable help
-
Tommix over 3 yearsdoesnt work.... shows there is no such extension methods.
-
Beedjees over 3 yearsAuthenticationResponseGrant is a property from IAuthenticationManager add by Microsoft.Owin (namespace : Microsoft.Owin.Security) docs.microsoft.com/en-us/previous-versions/aspnet/…
-
GisMofx almost 3 yearsI implemented Basic Auth and needed to access information about the user from
context
after signing in on the first POST. This resolved my issue.