c# - net - User.Identity.GetUserId() devuelve nulo después de iniciar sesión correctamente
mvc 5 login example in c# (7)
En realidad, el usuario no ha User.Identity
POST /Account/Login
, no en el contexto de la solicitud actual (la POST /Account/Login
) , que es donde User.Identity
obtiene sus datos. Si desea extraer la identificación del usuario que está intentando (y aparentemente tener éxito) SignInManager.PasswordSignInAsync
sesión, debe hacerlo de alguna otra manera, como secuestrar algún paso dentro de la llamada a SignInManager.PasswordSignInAsync
. Si está implementando su propio MembershipProvider
, esto debería ser fácil.
De lo contrario, tendrá que esperar a la próxima solicitud (cualquier solicitud manejada por algún método de Acción del Controlador debería funcionar bien) para usar User.Identity
de la forma que desee.
Alguna explicación añadida
Cuando se llama a su método de Login
, el contexto de la solicitud ya está evaluado y hay una gran cantidad de datos disponibles. Por ejemplo, encabezados HTTP, cookies, etc. Aquí es donde se encuentra toda la información de contexto, como User.Identity
.
Cuando llama a SignInManager.PasswordSignInAsync(...)
, esto no afecta los valores del contexto de solicitud , ya que esto no tendría sentido, ya que el navegador no ha cambiado de opinión acerca de lo que envió hace unos pocos milisegundos. Lo que sí afecta es el contexto de respuesta para agregar una cookie que contiene algún usuario e id de sesión. Esta cookie se envía al navegador, que luego la envía de vuelta al servidor para cada solicitud sucesiva. Por lo tanto, todas las solicitudes posteriores a esta (hasta que el usuario User.Identity
la User.Identity
o la cookie sea demasiado antigua) incluirán información para que el User.Identity
la User.Identity
.
He definido una variable temporal para obtener el ID de usuario actual, siempre devuelve nulo.
Aquí está la instantánea:
¿Por qué?
ACTUALIZAR:
//
// 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." });
}
}
ACTUALIZACIÓN 2:
En el lado del cliente, uso ajax para conectarme a /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 en el lado del cliente:
var signalR = $.connection.chat;
var signin = function (callback) {
$.connection.hub.start().done(function () {
signalR.server.signinToSignalR();
callback()
})
};
SignalR en el lado del servidor:
public void SigninToSignalR()
{
// this''s always null
string userId = HttpContext.Current.User.Identity.GetUserId();
}
En su caso, puede usar otros datos para encontrar al usuario que acaba de iniciar sesión. Como sabemos que el inicio de sesión es exitoso y el nombre de usuario es único, funcionará lo siguiente
//
// 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." });
}
}
Esto es lo que funcionó para mí:
await SignInManager.SignInAsync(user, isPersistent: true, rememberBrowser: false);
AuthenticationManager.User = new GenericPrincipal(AuthenticationManager.AuthenticationResponseGrant.Identity, null);
Una vez ejecutado, obtienes un estado autenticado para la solicitud actual.
Obtengo que el usuario haga lo siguiente justo después de iniciar sesión:
var userId = SignInManager.AuthenticationManager.AuthenticationResponseGrant.Identity.GetUserId();
var user = SignInManager.UserManager.Users.Where(x => x.Id.Equals(userId)).FirstOrDefault();
Sí, como dijo Anders, User.Identity y User.IsInRole no funcionarán dentro de la misma acción de inicio de sesión. Por lo tanto, debe redirigir a una nueva acción. Por lo tanto, la acción de inicio de sesión agrega:
return RedirectToAction ("MyNewLoginRoute", new {returnUrl = returnUrl});
A continuación se muestra un ejemplo de código:
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 });
Y ahora agregue una nueva acción LoginRoute como a continuación:
// 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);
}
}
Espero que esto pueda ayudar a alguien.
Simplemente intente esto:
string userId = SignInManager
.AuthenticationManager
.AuthenticationResponseGrant.Identity.GetUserId();
HttpContext.User = await _signInManager.CreateUserPrincipalAsync(user);
Después de iniciar sesión, puede usar el administrador de inicio de sesión para crear el principal de usuario y asignar manualmente la referencia HttpContext.User
Esto le permitirá acceder al ID de usuario como lo haría con una página de inicio de sesión normal
var userId = userManager.GetUserId(HttpContext.User);