2015-11-27 26 views
23

Ho definito una variabile temporanea per ottenere l'id utente corrente, restituisce sempre null.User.Identity.GetUserId() restituisce null dopo l'accesso con esito positivo

Ecco l'istantanea:

userId

Perché?

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:

Sul lato client, io uso ajax per la connessione 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 sul lato client:

var signalR = $.connection.chat; 
var signin = function (callback) { 
      $.connection.hub.start().done(function() { 
       signalR.server.signinToSignalR(); 
       callback() 
      }) 
     }; 

SignalR sul lato server:

public void SigninToSignalR() 
    { 
     // this's always null 
     string userId = HttpContext.Current.User.Identity.GetUserId(); 
    } 
+4

si prega di mostrare il codice come testo, non come immagine. –

risposta

23

In realtà, l'utente è non firmato a - non nel contesto della richiesta corrente(la richiesta POST /Account/Login), che è dove User.Identity ottiene i suoi dati Se desideri estrarre l'id dell'utente che sta attualmente tentando di eseguire (e apparentemente con successo) per accedere, devi farlo in qualche altro modo, come dirottare qualche passaggio all'interno della chiamata a SignInManager.PasswordSignInAsync. Se stai implementando il tuo MembershipProvider, questo dovrebbe essere facile.

In caso contrario, si dovrà attendere per la richiesta successiva(qualsiasi richiesta gestita con il metodo d'azione di qualche controller dovrebbe fare bene) utilizzare User.Identity nel modo che si desidera.

Qualche spiegazione aggiunto

Quando il tuo metodo di Login viene chiamato, il contesto di richiesta è già valutata e un sacco di dati sono disponibili. Ad esempio intestazioni HTTP, cookie e così via. Qui è dove vengono trovate tutte le informazioni di contesto, come User.Identity.

Quando si chiama SignInManager.PasswordSignInAsync(...), questo non effetto sui valori del contesto richiesta, perché questo non avrebbe alcun senso - dal momento che il browser non ha cambiato idea su ciò che ha inviato pochi millisecondi fa. Ciò che influenza è il contesto di risposta per aggiungere un cookie contenente un ID utente e di sessione. Questo cookie viene quindi inviato al browser, che quindi lo rimanda al server per ogni richiesta successiva. Quindi tutte le richieste successive a questa (fino a quando l'utente si disconnette o il cookie diventa troppo vecchio) includerà le informazioni per l'User.Identity da interpretare.

+0

Grazie! Puoi spiegarmi di più su "la richiesta corrente" e "la prossima richiesta"? Quando una richiesta è denominata "richiesta corrente" o "richiesta successiva"? –

+0

Beh, questo è solo inglese di base e temporalità. La richiesta "corrente" è la richiesta HTTP che il tuo codice * sta attualmente * gestendo - in questo caso è la richiesta "POST/Account/Login". Con la "prossima" richiesta intendo semplicemente la prossima richiesta di entrare più tardi nel tempo * (che va da microsecondi dopo a giorni successivi) * ... –

+0

ya. Penso che qualcosa sia sbagliato. Ti darò un esempio: dal lato del client, uso ajax per connettermi a '/ Account/Login'. Dopo aver effettuato il login con successo, uso di nuovo ajax per connecet to signalR hub ('/ Hubs/ChatHub.cs'). Ho definito un metodo per ottenere userId, ma è ancora nullo. 'public void SigninToSignalR() {string userId = HttpContext.Current.User.Identity.GetUserId(); } ' –

1

Sì, come ha detto Anders, User.Identity e User.IsInRole non funzioneranno all'interno della stessa azione di accesso. Quindi, è necessario reindirizzare a una nuova azione, quindi aggiungere l'azione di accesso interno:

return RedirectToAction ("MyNewLoginRoute", new {returnUrl = returnUrl});

seguito è riportato un esempio di codice:

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

E ora aggiungiamo una nuova LoginRoute azione come di seguito:

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

Spero che questo potrebbe aiutare qualcuno.

7

Nel tuo caso, potresti utilizzare altri dati per trovare l'utente che ha appena effettuato l'accesso. Poiché sappiamo che l'accesso è riuscito e il nome utente è unico, funzionerà quanto segue;

// 
// 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." }); 
    } 
} 
13

Semplicemente provare questo:

string userId = SignInManager 
.AuthenticationManager 
.AuthenticationResponseGrant.Identity.GetUserId(); 
+0

Grazie amico, finalmente uno semplice. –

0
HttpContext.User = await _signInManager.CreateUserPrincipalAsync(user); 

Dopo l'accesso è possibile utilizzare il segno in Manager per creare il principale utente e assegnare manualmente il riferimento HttpContext.User

Questa volontà quindi consenti di accedere all'id utente come faresti con una normale pagina registrata

var userId = userManager.GetUserId(HttpContext.User); 
0

ottengo l'utente facendo quanto segue subito dopo di accesso:

var userId = SignInManager.AuthenticationManager.AuthenticationResponseGrant.Identity.GetUserId(); 
var user = SignInManager.UserManager.Users.Where(x => x.Id.Equals(userId)).FirstOrDefault();