【问题标题】:Proper way to get current User ID in Entity Framework Core在 Entity Framework Core 中获取当前用户 ID 的正确方法
【发布时间】:2019-05-31 01:29:47
【问题描述】:

对于 ASP.NET Core 的不同 RC,关于如何获取当前登录用户的 ID,这里有很多不同的答案。我想在这里问一个明确的问题。请注意 project.json 现在有 "Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0"

使用 RC1,您可以执行以下操作:

using Microsoft.AspNet.Identity;
using System.Security.Claims;

User.GetUserId();

但是对于新发布的 EF Core 版本 1,Microsoft.AspNet.Identity 不是正确的版本。

有人建议使用 UserManager,这似乎只是为了获取当前登录的用户:

private Task<ApplicationUser> GetCurrentUserAsync() => _userManager.GetUserAsync(HttpContext.User);

var user = await GetCurrentUserAsync();
var userId = user?.Id;

我发现的另一种方法是:

private readonly UserManager<ApplicationUser> _userManager;
_userManager.GetUserId(User)

那么对于 ASP.NET Core 1 RTM 和 EF Core 1 以及 project.json 中的以下库,获取当前登录用户 id 的正确方法是什么?

"Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0",
"Microsoft.AspNetCore.Mvc": "1.0.0",

【问题讨论】:

标签: asp.net-core asp.net-identity entity-framework-core


【解决方案1】:

如果您通过 Controller 访问它,那么使用 UserManager 来获取用户 ID 是非常低效的,因为您正在往返于数据库。如果您使用 ClaimsIdentity,您可以执行以下操作来获取用户 ID:

var claimsIdentity = (ClaimsIdentity)this.User.Identity;
var claim = claimsIdentity.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier);
var userId = claim.Value;

此方法仅读取 cookie 中已经存在的用户 ID,然后自动反序列化并存储在 ClaimsIdentity 实例中。

我使用这个辅助类:

public static class UserHelpers
{
    public static string GetUserId(this IPrincipal principal)
    {
        var claimsIdentity = (ClaimsIdentity)principal.Identity;
        var claim = claimsIdentity.FindFirst(System.Security.Claims.ClaimTypes.NameIdentifier);
        return claim.Value;
    }
}

所以获取用户ID变成:

var userId = this.User.GetUserId();

如果由于某种原因所需的声明不在 Claims 集合中,您可以在创建用户的 ClaimsIdentity 时轻松添加它:

public class ApplicaionUser : IdentityUser
{
    public async Task<ClaimsIdentity> GenerateUserIdentityAsync(UserManager<User> manager)
    {
        var userIdentity = await manager.CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
        userIdentity.AddClaim(new Claim(ClaimTypes.NameIdentifier, this.UserId));
        return userIdentity;
    }
}

【讨论】:

  • 我很惊讶没有内置的方法来获取当前登录的用户 ID。这种方法与旧的 Users.Identity.GetUserId() 的工作方式或行为方式有什么不同吗?
  • 此方法使用与旧GetUserId相同的基本逻辑。不同之处在于您可以直接在 User 对象而不是 User.Idenity 对象上调用它。检查此答案以进行比较stackoverflow.com/a/28520274/1396972。我相信他们删除它的原因是因为对 ClaimsIdentity 的强制转换违反了 LSP。
  • 将此用于框架 4.5.2 上的 asp.net 核心应用程序。添加 nuget 包 Microsoft.AspNet.Identity 会导致歧义并与现有框架引用发生冲突。
  • 而在 2020 年(ASP.NET Core 3.1),人们仍在努力解决同样的问题!看起来这仍然是最好的答案。为什么他们不向User.Identity 添加“Id”属性完全是个谜。
【解决方案2】:

ASP.NET Core Identity 通过 DI 在 startup.cs 中注入 - 因此您只需通过构造函数注入 UserManager

UserManager<ApplicationUser> userManager

然后您可以在方法中使用以下内容

_userManager.GetUserId(User);

当您使用个人用户帐户创建新的 ASP.NET Core 1 项目时,它在示例 Web 应用程序中使用的方式。

【讨论】:

    【解决方案3】:

    下面的单行是上面其他答案的更简洁版本。

    var user = User.FindFirst(ClaimTypes.NameIdentifier).Value;
    

    为了进一步解释,我想使用最基本的身份验证形式,而数据库中没有任何表,所以我选择了这个 - Using Cookie Authentication without ASP.NET Core Identity 来自核心文档。

    要使其正常工作,第一步是在 Startup.cs 中添加服务

    services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
        .AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
            {
            options.LoginPath = new PathString("/Account/Login/");
            options.LogoutPath = new PathString("/Account/Logoff/");
            options.AccessDeniedPath = new PathString("/Account/AccessDenied/");
            options.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
            });
    
    services.ConfigureApplicationCookie(identityOptionsCookies =>
    {
        // See https://andrewlock.net/automatically-validating-anti-forgery-tokens-in-asp-net-core-with-the-autovalidateantiforgerytokenattribute/
        identityOptionsCookies.Cookie.SecurePolicy = CookieSecurePolicy.SameAsRequest;
    });
    

    然后在回传的 AccountController 中输入有效的用户 ID 和密码,最简单的基于声明的身份验证就是将登录 ID 添加为声明,例如

    var 声明 = 新列表 { 新的声明(ClaimTypes.NameIdentifier,loginViewModel.Guid,ClaimValueTypes.String,颁发者), };

                var claimsIdentity = new ClaimsIdentity(claims, CookieAuthenticationDefaults.AuthenticationScheme);
    
                var principal = new ClaimsPrincipal(claimsIdentity);
    
                await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, principal,
                    new AuthenticationProperties
                    {
                        ExpiresUtc = DateTime.UtcNow.AddMinutes(_cookieTimeoutInMinutes),
                        IsPersistent = true,
                        AllowRefresh = false
                    });
    

    登录完成后,您可以按照上面一行中的说明检索用户 ID。有关更详细的步骤,请参阅上面 Milos Mrdovic 的答案。

    var user = User.FindFirst(ClaimTypes.NameIdentifier).Value;
    

    更多信息请参见Claims-Based Authorization

    【讨论】:

    • 完成@PetterFriberg :)。
    【解决方案4】:

    您也可以通过这种方式获取UserId。

    public class Program
       {
               private readonly SignInManager<ApplicationUser> _signInManager;
    
               public Program(SignInManager<ApplicationUser> signInManager)
               {
                   _signInManager = signInManager;
                  var UserId = _signInManager.Context.User.Claims.FirstOrDefault().Value;
               }
       }
    

    ApplicationUser 类在下面给出......

    public class ApplicationUser:IdentityUser
        {
            [Column(TypeName = "Nvarchar(500)")]
            public string FirstName { get; set; }
            [Column(TypeName = "Nvarchar(500)")]
            public string MiddleName { get; set; }
            [Column(TypeName = "Nvarchar(500)")]
            public string LastName { get; set; }
            [Column(TypeName = "DateTime")]
            public DateTime? LastAccess { get; set; }
        }
    

    并且您的 ApplicationUser 类应该由 IdentityUser 继承。

    【讨论】:

      猜你喜欢
      • 2022-01-20
      • 1970-01-01
      • 2017-11-22
      • 1970-01-01
      • 1970-01-01
      • 2015-08-22
      • 2018-10-16
      • 1970-01-01
      • 2016-12-21
      相关资源
      最近更新 更多