簡體   English   中英

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

[英]User.Identity.GetUserId() returns null after successful login

我定義了一個臨時變量來獲取當前用戶 ID,它總是返回 null。

這是快照:

用戶身份

為什么?

更新:

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

事實上,用戶沒有登錄-在當前請求上下文POST /Account/Login請求),這是在User.Identity獲取數據。 如果您想提取當前嘗試(並且顯然成功)登錄的用戶的 id,您需要以其他方式執行此操作,例如劫持SignInManager.PasswordSignInAsync調用中的某個步驟。 如果您正在實現自己的MembershipProvider ,這應該很容易。

否則,您將不得不等待下一個請求(由某些 Controller 的 Action 方法處理的任何請求都應該可以)以您想要的方式使用User.Identity

一些補充說明

當您的Login方法被調用時,請求上下文已經被評估並且大量數據可用。 例如 HTTP 標頭、cookie 等。 在這里可以找到所有上下文信息,例如User.Identity

當你調用SignInManager.PasswordSignInAsync(...)並不影響請求上下文的值,因為這將毫無意義-因為瀏覽器並沒有改變其主意是什么發出的幾毫秒前。 它確實影響的是添加包含一些用戶和會話 ID 的cookie響應上下文 然后將此 cookie 發送到瀏覽器,然后瀏覽器將其發送回服務器以用於每個后續請求。 因此,晚於該請求的所有請求(直到用戶退出或 cookie 變得太舊)都將包含供User.Identity解釋的信息。

簡單地試試這個:

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

在您的情況下,您可以使用其他數據來查找剛剛登錄的用戶。由於我們知道登錄成功並且用戶名是唯一的,因此以下將起作用;

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

登錄后,您可以使用登錄管理器創建用戶主體並手動分配 HttpContext.User 引用

這將允許您像使用普通登錄頁面一樣訪問用戶 ID

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

是的,正如安德斯所說,User.Identity 和 User.IsInRole 在同一個登錄操作中不起作用。 所以,你需要重定向到一個新的動作,所以在登錄動作中添加:

return RedirectToAction("MyNewLoginRoute", 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);
        }
    }

希望這可以幫助某人。

我讓用戶在登錄后立即執行以下操作:

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

對於那些正在實施自定義身份驗證提供程序但仍然不明白為什么 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);

這對我有用:

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

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

執行后,您將獲得當前請求的身份驗證狀態。

最后,我找到了解決方案。 實際上,以上答案都不適合我。

  1. 我在我的解決方案中添加了一個帶有身份的新項目。
  2. 在我的數據庫層中將身份設置為我的 ApplicationUser.cs

在此處輸入圖片說明

  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. 很難設置和配置以上所有內容,但需要支持並注意操作。 試試這個,它有效。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM