如何在成功登录后立即在控制器中获取身份识别用户ID?

22

我正在使用Identity v2和MVC 5进行外部登录。

在我的外部登录回调函数中,我使用以下代码将用户登录:

var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);

然后有一个用于result的开关,我需要在success情况下访问用户的ID,但是User.Identity.GetUserId();在这里为null。

我该如何在这种情况下访问用户的ID?


你需要创建一个自定义的ExternalSignInAsync方法,该方法将返回一个包含用户ID和成功结果的模型。请检查Install-Package Microsoft.AspNet.Identity.Samples nuget包以获取更多详细信息。 - DSR
5个回答

44

成功登录后,如果想即时获取有关已登录身份的索赔数据和其他信息而不需要访问数据库,只需访问signinManager.AuthenticationManager.AuthenticationResponseGrant.Identity

例如,

switch (result) { case SignInStatus.Success: var userId = signinManager.AuthenticationManager.AuthenticationResponseGrant .Identity.GetUserId(); // ...

您还可以在此其他问题的答案中看到它被用于在登录后立即向标识添加新声明 - AuthenticationManager.AuthenticationResponseGrant.Identity.AddClaims(freshClaims);


这绝对是最简单的解决方案! - kloarubeek
谢谢 - 这正是我想要的。 - Aaron
找了好久终于找到了。我使用了以下代码:Dim IDClaim As Claim = signInManager.AuthenticationManager.AuthenticationResponseGrant.Identity.Claims.FirstOrDefault(Function(o) o.Type = ClaimTypes.NameIdentifier) Dim UserID As Integer = Convert.ToInt32(IDClaim.Value)谢谢! - Resource
signInManager.AuthenticationManager在Core 2.2中似乎不再存在。如果您需要一行代码,可以使用@A. Burak Erbora的答案。 - Simopaa

5
我使用System.Security.Claims.ClaimTypes.NameIdentifier对象来保存我的用户ID。
我创建了一个帮助类来访问其中的值。
public class UserHelper
  {
    public static string GetUserId()
    {
      var identity = (System.Security.Claims.ClaimsPrincipal)System.Threading.Thread.CurrentPrincipal;
      var principal = System.Threading.Thread.CurrentPrincipal as System.Security.Claims.ClaimsPrincipal;
      var userId = identity.Claims.Where(c => c.Type == System.Security.Claims.ClaimTypes.NameIdentifier).Select(c => c.Value).SingleOrDefault();
      return userId;
    }
    public static string GetUserName()
    {
      var identity = (System.Security.Claims.ClaimsPrincipal)System.Threading.Thread.CurrentPrincipal;
      var principal = System.Threading.Thread.CurrentPrincipal as System.Security.Claims.ClaimsPrincipal;
      var name = identity.Claims.Where(c => c.Type == System.Security.Claims.ClaimTypes.Name).Select(c => c.Value).SingleOrDefault();
      return name;
    }
    public static string GetUserMail()
    {
      var identity = (System.Security.Claims.ClaimsPrincipal)System.Threading.Thread.CurrentPrincipal;
      var principal = System.Threading.Thread.CurrentPrincipal as System.Security.Claims.ClaimsPrincipal;
      var mail = identity.Claims.Where(c => c.Type == System.Security.Claims.ClaimTypes.Email).Select(c => c.Value).SingleOrDefault();
      return mail;
    }
  }

我称之为,并使用以下方式调用:

var user = UserHelper.GetUserId();

1

好的,我找到了一种方法;我可以通过以下方式获取它:

one
var userID = UserManager.FindByEmail(loginInfo.Email).Id;

但是,我认为这不是最好的解决方案,因为它似乎需要使用两个查询来访问数据库。有没有人能提供更好的解决方案呢?


不是一个好的方法。您不应该去数据库查找UserID。UserID和电子邮件已经存在于身份声明中。 - Serdar Çatalpınar
@Serdar Çatalpınar:恰恰是我寻求更好方法的意思。感谢您的回答。 - A. Burak Erbora

1
你可以使用以下代码。
在Identity.Config.cs中为ApplicationSignInManager类添加函数。
 public override Task SignInAsync(ApplicationUser user, bool isPersistent, bool rememberBrowser)
 {
            var claims = new List<Claim>()
            {
                new Claim(ClaimTypes.NameIdentifier, user.Id),
                new Claim(ClaimTypes.Email, user.Email)
            };
            this.AuthenticationManager.User.AddIdentity(new ClaimsIdentity(claims));
            return base.SignInAsync(user, isPersistent, rememberBrowser);
}

尝试一下这段代码。
private ClaimsPrincipal GetCurrentUser()
        {
            var context = HttpContext.GetOwinContext();
            if (context == null)
                return null;

            if (context.Authentication == null || context.Authentication.User == null)
                return null;

            return context.Authentication.User;
        }
        private string GetUserId()
        {
            var user = GetCurrentUser();
            if (user == null)
                return null;

            var claim = user.Claims.FirstOrDefault(o => o.Type == ClaimTypes.NameIdentifier);
            if (claim == null)
                return null;

            return claim.Value;
        }

        private string GetUserEmail()
        {
            var user = GetCurrentUser();
            if (user == null)
                return null;

            var claim = user.Claims.FirstOrDefault(o => o.Type == ClaimTypes.Email);
            if (claim == null)
                return null;

            return claim.Value;
        }

不幸的是,我太快接受了这个。无论我做什么,Identity.GetUserId<T>(); 在登录成功后立即给我返回 null。我猜它等待着登录过程中的某个特定阶段才能工作。 - A. Burak Erbora
问题似乎在于当调用signinmanager的signin方法并返回成功结果时,它不会更新身份用户对象以进行身份验证。您有任何想法如何强制在那里更新它吗? - A. Burak Erbora
你可以在上面的代码中尝试。我改变了代码行。 - Serdar Çatalpınar
太好了,我有一种感觉可以使用内置的认领系统来完成这个,谢谢! - A. Burak Erbora

-1
在dotnet 5中,我在使用SignInManager登录后跟随上下文。
 var result =
            await _signInManager.PasswordSignInAsync(model.UserName, model.Password, true, lockoutOnFailure: true);
        if (result.Succeeded)
        {
            var userId = _signInManager.UserManager.Users.FirstOrDefault()?.Id; }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接