简体   繁体   中英

User.Identity.GetUserId() returns null after successful login

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

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.

Simply try this :

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

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

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.

I get the user doing the following right after sign-in:

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

For those who are implementing custom auth provider and still did not get it why User.Identity.GetUserId() is returning null after successful login

You just need to add ClaimType.NameIdentifier while adding a claim, see below line:

identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Email));

Adding below code just for reference:

    var identity = new ClaimsIdentity(context.Options.AuthenticationType);
      
      /*Following line(ClaimTypes.NameIdentifier) is the reason to return UserId for User.Identity.GetUserId()*/
       identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Email));

      var props = new AuthenticationProperties(new Dictionary<string, string>
                        {
                            {
                                "UserName", user.Name
                            },
                            /*add more user info here*/
                         });

 var ticket = new AuthenticationTicket(identity, props);
 context.Validated(ticket);

Here's what worked for me:

await SignInManager.SignInAsync(user, isPersistent: true, rememberBrowser: false);

AuthenticationManager.User = new GenericPrincipal(AuthenticationManager.AuthenticationResponseGrant.Identity, null);

Once executed, you get authenticated state for the current request.

Finally, I found the solution. Actually none of the above answers work for me.

  1. I add a new project with identity to my solution.
  2. Set the identity to my ApplicationUser.cs in my database Layer

在此处输入图片说明

  1. add this to my startup.cs

     Configuration.GetConnectionString("DefaultConnection"))); //services.AddDefaultIdentity<ApplicationUser>( options => options.SignIn.RequireConfirmedAccount = true ) // .AddEntityFrameworkStores<ApplicationDbContext>( ); services.AddIdentity < ApplicationUser, IdentityRole > (options = >{ options.Password.RequireDigit = false; options.Password.RequiredLength = 4; options.Password.RequireNonAlphanumeric = false; options.Password.RequireUppercase = false; options.Password.RequireLowercase = false; options.SignIn.RequireConfirmedAccount = false; }).AddEntityFrameworkStores < ApplicationDbContext > ().AddDefaultTokenProviders();```
  2. it was hard to set and config all above but need to be brace and watchful to the operations. Try this, it works.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM