成功登录后,User.Identity.GetUserId()返回null

时间:2015-11-27 07:02:37

标签: c# asp.net-mvc asp.net-mvc-5 identity

我已经定义了一个临时变量来获取当前用户ID,它总是返回null。

以下是快照:

userId

为什么?

更新

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

更新2:

在客户端,我使用ajax连接到/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:

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

服务器端的SignalR:

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

9 个答案:

答案 0 :(得分:27)

实际上,用户已登录 - 不在当前请求 POST /Account/Login请求)的上下文中,User.Identity获取其数据的地方。如果要提取当前正在尝试(并且显然是成功的)的用户的id以进行登录,则需要以其他方式执行此操作,例如劫持调用{{1 }}。如果您要实现自己的SignInManager.PasswordSignInAsync,这应该很容易。

否则,您将不得不等待下一个请求 (某些控制器的Action方法处理的任何请求应该没问题)使用{{1以你想要的方式。

一些补充说明

当调用MembershipProvider方法时,已经评估了请求上下文并且有大量数据可用。例如HTTP标头,cookie等。这是找到所有上下文信息的地方,例如User.Identity

当您致电Login时,会影响请求上下文的值,因为这没有任何意义 - 因为浏览器没有更改关于它在几毫秒前发送的内容。它影响的是响应上下文,以添加包含一些用户和会话ID的 Cookie 。然后将此cookie发送到浏览器,然后浏览器将每个连续请求发送回服务器。因此,所有请求晚于此(直到用户退出或cookie过时)将包含User.Identity要解释的信息。

答案 1 :(得分:24)

试试这个:

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

答案 2 :(得分:9)

在您的情况下,您可以使用其他数据来查找刚刚登录的用户。由于我们知道登录成功且用户名是唯一的,因此以下内容将起作用;

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

答案 3 :(得分:2)

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

登录后,您可以使用登录管理器创建用户主体并手动分配HttpContext.User参考

这样您就可以像访问普通登录页面一样访问用户ID

{{1}}

答案 4 :(得分:1)

是的,正如Anders所说,User.Identity和User.IsInRole在同一个登录操作中不起作用。 因此,您需要重定向到新操作,因此在登录操作中添加:

返回RedirectToAction(&#34; MyNewLoginRoute&#34;,new {returnUrl = returnUrl});

下面是一个代码示例:

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

现在添加一个新动作LoginRoute如下:

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

希望这可以帮助某人。

答案 5 :(得分:1)

对于那些正在实现自定义身份验证提供程序的用户,仍然无法获取的原因,为什么User.Identity.GetUserId()成功登录后会返回null

您只需要在添加声明时添加ClaimType.NameIdentifier,请参见以下行:

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

添加以下代码仅供参考:

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

答案 6 :(得分:0)

我让用户在登录后立即执行以下操作:

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

答案 7 :(得分:0)

这对我有用:

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

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

执行后,您将获得当前请求的身份验证状态。

答案 8 :(得分:0)

最后,我找到了解决方案。 上面的答案实际上对我没有用。

  1. 我在解决方案中添加了一个具有标识的新项目。
  2. 将身份设置为数据库层中的ApplicationUser.cs

enter image description here

  1. 将此添加到我的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. 很难对以上所有内容进行设置和配置,但需要大胆并注意操作。试试这个,它有效。