我在想,也許我關于如何解決這個問題的整個想法都是錯誤的,所以讓我解釋一下我想要做什么。
我有一個 UserId,它是我的 JWT 令牌中包含的一個屬性。
在我的許多 REST 端點上,我需要讀取該 UserId 才能在我的資料庫查詢中使用它。
我實作了一個過濾器,它攔截我的所有呼叫并解碼我的 JWT,并將 UserId 值分配給我創建的靜態 Globals 類。
不過,我現在才意識到,該課程是全球性的。就像在,對于任何人的 REST 請求,這些值實際上是在整個服務器上共享的。我打算讓這個值在每個單獨的請求期間基本上只是暫時可用的。
如何更改我的實作,以便我可以全域訪問當前請求的 JWT 令牌中包含的 UserId。
uj5u.com熱心網友回復:
我的建議是進行某種抽象,例如ICurrentUser并進行實施,這UserId將從HttpContext.
// Define in Domain/Application project
public interface ICurrentUser
{
public string? Id { get; set; }
}
// Implement in ASP.NET project
public class CurrentUser : ICurrentUser
{
public CurrentUser(IHttpContextAccessor contextAccessor)
{
var user = contextAccessor.HttpContext?.User;
if (user == null)
{
return;
}
Id = user.FindFirstValue(ClaimTypes.NameIdentifier) ?? user.FindFirstValue(JwtClaimTypes.Subject);
}
public string? Id { get; set; }
}
另外,不要忘記.AddHttpContextAccessor()為您添加呼叫服務
uj5u.com熱心網友回復:
如果您希望在單個請求期間可以使用某些東西,我建議您使用注冊為 scoped 的服務請參閱作用域服務
但讓我們從頭開始。首先實作一個服務本身,如:
public UserService : IUserService
{
private readonly IHttpContextAccessor _accessor;
/// inject the `IHttpContextAccessor` to access the actual
/// request / token / headers etc.
public UserService(IHttpContextAccessor accessor)
{
_accessor = accessor;
}
public async Task<string> GetUserIdAsync()
{
var userId = await GetUserIdFromTokenAsync();
return userId;
}
private Task<string> GetUserIdFromTokenAsync()
{
/// Add your logic here to get or parse the
/// user id from the token or do some other stuff to get the user id.
/// ... or get the user id from the current User object claim
/// depends on your auth settings `_accessor.HttpContext?.User`
var token = _accessor... // from headers?
return userId;
}
}
/// Always use an interface to make it well testable and mockable for unit tests
public interface IUserService
{
Task<string> GetUserIdAsync();
}
然后在您的依賴注入部分(Startup.cs或Program.cs取決于您選擇的模板)。
/// register the `IHttpContextAccessor` to be able to inject it.
services.AddHttpContextAccessor();
/// register your `UserService` as scoped!
services.AddScoped<IUserService, UserService>();
現在您可以在所有服務和控制器中使用它(至少也注冊為作用域)。這將解決每個請求的服務。
/// In a data service
class YourDataService
{
private readonly IUserService _userService;
/// Inject the `IUserService` wherever you need it now to
/// receive the current user Id.
public YourDataService(IUserService service)
{
_userService = service
}
public async Task DoYourQueryStuffAsync()
{
var userId = await _userService.GetUserIdAsync();
/// Your application logic with the provided userId
///
}
}
/// The same applies for a controller
[ApiController]
[Route("values")]
public class ValuesController : ControllerBase
{
private readonly IUserService _userService;
/// Inject the `IUserService` wherever you need it now to
/// receive the current user Id.
public ValuesController(IUserService service)
{
_userService = service
}
[Authorized]
[HttpGet]
public async Task<IActionResult> Query()
{
var userId = await _userService.GetUserIdAsync();
/// Your application logic with the provided userId
///
var queryresult = await ...
return Ok(queryresult);
}
}
最后的注釋:不要陷入從單例服務中使用作用域服務的陷阱,這是行不通的,因為單例在沒有請求背景關系的情況下是持久的。
檔案鏈接:
- ASP.net 核心依賴注入
- Bearer中的UserId
轉載請註明出處,本文鏈接:https://www.uj5u.com/shujuku/531713.html
上一篇:如何在回圈中命令Ajax呼叫
