簡體   English   中英

如何使用 ASP.NET Core 從 DbContext 中的 JWT 獲取用戶名?

[英]How to get username from JWT in DbContext using ASP.NET Core?

MyDbContext 中,我有方法 LogChanges,它使用以下信息記錄我的日志表中的任何更改:

TableName = entityName,
IDRow = JsonConvert.SerializeObject(primaryKeys),
Value = JsonConvert.SerializeObject(values),
Date = dateTimeNow,
Author = userFromJWT

我想將作者設置為獲得 JWT 授權的用戶 從這部分開始:

“子”:“我的用戶名”

如何在MyDbContext 中獲取該用戶名? 也許是某種依賴注入?

提前致謝!

@解決方案

啟動文件

   public void ConfigureServices(IServiceCollection services) {
       // ...
       services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
           .AddJwtBearer(options => {
          options.TokenValidationParameters = new TokenValidationParameters {
            ValidateIssuer = true,
            ValidateAudience = true,
            ValidateLifetime = true,
            ValidateIssuerSigningKey = true,
            ValidIssuer = Configuration["Jwt:Issuer"],
            ValidAudience = Configuration["Jwt:Issuer"],
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
          };
        });
      services.AddHttpContextAccessor();
      //...
    }

MyDbContext.cs

// ...
private readonly IHttpContextAccessor _httpContext;

public MyDbContext(DbContextOptions options, IHttpContextAccessor httpContext) : base(options) {
  _httpContext = httpContext;
}
//..

並從我使用的 JWT 的聲明(來自“sub”)中獲取名稱

_httpContext.HttpContext.User.Claims.SingleOrDefault(
        c => c.Type == "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier")?.Value

假設您實際上已經集成到 ASP.NET Core 身份驗證子系統(即services.AddAuthenticationapp.UseAuthentication ),那么這實際上是為您處理的。 將讀取 JWT 以從中構建ClaimsPrincipal實例,然后將其存儲在HttpContext.User 因此,用戶的用戶HttpContext.User.Identity.Name位於HttpContext.User.Identity.Name的標准位置,或者您可以通過HttpContext.User.Identity上的Claims集合直接訪問它(和任何其他聲明)。

如果問題是您在無法直接訪問HttpContext.User地方(基本上在控制器或視圖之外的任何地方)需要此信息,那么您只需要注入IHttpContextAccessor 這需要兩件事:

  1. 您必須添加IHttpContextAccessor服務。 出於性能原因,默認情況下不包含它。 (這並不是說它對性能有嚴重影響。只是如果你碰巧不需要它,你可以通過不包括它來獲得更多的性能。ASP.NET Core 就是只包括你的需要包括。)無論如何:

    ASP.NET 核心 2.1

     services.AddHttpContextAccessor();

    之前的版本

    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
  2. 無論您在哪里注入它都需要成為請求管道的一部分,否則HttpContext將不存在。 這應該不是問題,因為無論如何你都依賴於 JWT 的存在。 請記住,您不能在常規控制台應用程序等中使用它。

是的,我在@Chris Prat 的解決方案中看到的唯一問題是,您現在需要在與它實際上無關的項目中引用 Asp.Net.Core 程序集。 對我來說,更好的解決方案是定義一個具有所需屬性的新類。 然后使用 DI/IOC 將其注冊為 Func 並將其傳遞給 DBContext。 IE。

public class UserInfo
{
    public Guid UserId{get;set;}
    public string UserName{get;set;
}

然后在 Startup.cs 中做這樣的事情:

public IServiceProvider ConfigureServices(IServiceCollection services)
{
    ... services registration part ommited

    var builder = new ContainerBuilder();
    builder.Populate(services);
    builder.Register(context=>
    {
        var identityUser = context.Resolve<IHttpContextAccessor>()?.HttpContext?.User;
        var userInfo = new UserInfo()
        {
            Name=//get it from identityUser.Claims 
            Id= //get it from identityUser.Claims
        }
        return userInfo;
    }).AsSelf()
      .InstancePerLifetimeScope();
}

然后在 DbContext 中你有這個(這里我使用 Autofac IOC 容器,但任何可以注冊工廠的容器都可以像 StructureMap、Ninject、Autofac ......):

public class MyDbContext: DbContext
{
    private readonly Func<UserInfo> _userInfoFactory;
    private UserInfo UserInfo => _userInfoFactory();

    public MyDbContext(DbContextOptions options, Func<UserInfo> userInfoFactory) : base(options) 
    {
        this._userInfoFactory = userInfoFactory;
    }

    public void SomeMethod()
    {
        var someEntity = new SomeEntity()
        {
           ChangedByUserId = this.UserInfo.Id
           ...
        }
     }  
}

這是一些更簡潔的解決方案,可導致項目之間更多的解耦。

添加到您的 Startup.cs ConfigureServices 方法

services.AddHttpContextAccessor();

在您的存儲庫中,在構造函數中使用依賴注入來添加 IHttpContentAccessor,您可以從聲明中獲取 UserId

public ModelRepository(DataContext dataContext, ILogger<ModelRepository> logger, IHttpContextAccessor httpContextAccessor)
        {
            _dataContext = dataContext ?? throw new ArgumentNullException(nameof(dataContext));
            _logger = logger;

            if(httpContextAccessor.HttpContext.User.Identity.IsAuthenticated)
            {
                userId = httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
            }           
        }

如果您需要來自用戶的更多信息,您也可以注入 UserManager

public ModelRepository(DataContext dataContext, ILogger<ModelRepository> logger, IHttpContextAccessor httpContextAccessor, UserManager<ApplicationUser> userManager)
        {
            _dataContext = dataContext ?? throw new ArgumentNullException(nameof(dataContext));
            _logger = logger;

            if(httpContextAccessor.HttpContext.User.Identity.IsAuthenticated)
            {
                userId = httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
                user = await userManger.FindByIdAsync(userId);
            }           
        }

暫無
暫無

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

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