[英]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.AddAuthentication
和app.UseAuthentication
),那么這實際上是為您處理的。 將讀取 JWT 以從中構建ClaimsPrincipal
實例,然后將其存儲在HttpContext.User
。 因此,用戶的用戶HttpContext.User.Identity.Name
位於HttpContext.User.Identity.Name
的標准位置,或者您可以通過HttpContext.User.Identity
上的Claims
集合直接訪問它(和任何其他聲明)。
如果問題是您在無法直接訪問HttpContext.User
地方(基本上在控制器或視圖之外的任何地方)需要此信息,那么您只需要注入IHttpContextAccessor
。 這需要兩件事:
您必須添加IHttpContextAccessor
服務。 出於性能原因,默認情況下不包含它。 (這並不是說它對性能有嚴重影響。只是如果你碰巧不需要它,你可以通過不包括它來獲得更多的性能。ASP.NET Core 就是只包括你的需要包括。)無論如何:
ASP.NET 核心 2.1
services.AddHttpContextAccessor();
之前的版本
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
無論您在哪里注入它都需要成為請求管道的一部分,否則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.