如何跟踪我的 API 消耗的 JWT
How to keep track of consumed JWT by my API
我的控制器方法使用在 Startup.cs
的 ConfigureServices 方法中启用的 JWT 令牌
.AddJwtBearer(options => { // some code }; });
UserController 中的 CreateUser() 操作使用此令牌
[HttpPost, Authorize("JWT")]
public SaveResponse CreateUser(IUnitOfWork uow, UserRequest request) {
return new UserRepository().Create(uow, request);
}
问题如下:在创建新用户时更深入一些方法,有一个方法 HasPermission() 检查登录用户的管理权限。但是,在这种使用 JWT 的特殊情况下,没有登录用户。存在有效的 JWT 就足够了。我将以某种方式修改此 HasPermission(),使其也接受 JWT。
在 CreateUser 方法级别,JWT 存在于 HttpRequest 的 'Authorization' header.
中
问题是 - 如何将此 JWT 令牌传递给 UserRepository().Create(uow, request) 执行的方法链中的第 8 个方法?有没有办法在不修改这些方法的参数的情况下实现这一目标?
谢谢
如果您使用 DI 实例化服务依赖项,您可以通过 services.AddHttpContextAccessor()
注册 IHttpContextAccessor
并使用它来获取有关请求的信息:
public SomeService(IHttpContextAccessor contextAccessor)
{
_contextAccessor = contextAccessor;
}
public void SomeServiceMethod()
{
var auth = _contextAccessor.HttpContext.Request.Headers[HeaderNames.Authorization].ToString(); // possibly will need to remove scheme from the header
}
This particular case using JWT, there's no logged in user. The presence of valid JWT suffices.
假设您启用了 auth 中间件,如果请求能够到达 CreateUser
操作,则 [Authorize]
属性确保令牌有效。所以你不需要再做一次验证。
其次,您不应该将令牌向下传送到存储库。将 HTTP 和数据检索问题分开。
不“将参数向下传递 8 级”的解决方案是 use dependency injection 在整个应用程序中并让它跟踪依赖项。
要访问存储库中的当前用户,请创建一个公开用户的界面:
interface IPrincipalAccessor {
ClaimsPrincipal? Principal { get; }
}
然后用 IHttpContextAccessor
实现
private class HttpPrincipalAccessor : IPrincipalAccessor
{
private IHttpContextAccessor _httpContextAccessor;
public HttpPrincipalAccessor(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public ClaimsPrincipal? Principal => _httpContextAccessor?.HttpContext?.User;
}
您需要启用 IHttpAccessor
并在 DI:
中注册此 class
services.AddHttpContextAccessor();
services.AddScoped<IPrincipalAccessor, HttpPrincipalAccessor>();
现在您可以在您的存储库中注入此接口并使用用户声明。回购不知道,也不关心用户来自哪里,它只需要知道当前用户。
class MyRepo
{
private IPrincipalAccessor _principalAccessor;
public MyRepo(IPrincipalAccessor principalAccessor)
{
_principalAccessor = principalAccessor;
}
Task Create(/* some parameters */)
{
var user = _principalAccessor.Principal;
if (user.HasClaim("eyes", "2"))
{
// user has two eyes
}
// ...
}
}
但是你的代码的问题是你没有使用依赖注入,所以你需要注入你的 repo,而不是 new
把它搞起来。
我的控制器方法使用在 Startup.cs
的 ConfigureServices 方法中启用的 JWT 令牌.AddJwtBearer(options => { // some code }; });
UserController 中的 CreateUser() 操作使用此令牌
[HttpPost, Authorize("JWT")]
public SaveResponse CreateUser(IUnitOfWork uow, UserRequest request) {
return new UserRepository().Create(uow, request);
}
问题如下:在创建新用户时更深入一些方法,有一个方法 HasPermission() 检查登录用户的管理权限。但是,在这种使用 JWT 的特殊情况下,没有登录用户。存在有效的 JWT 就足够了。我将以某种方式修改此 HasPermission(),使其也接受 JWT。
在 CreateUser 方法级别,JWT 存在于 HttpRequest 的 'Authorization' header.
中问题是 - 如何将此 JWT 令牌传递给 UserRepository().Create(uow, request) 执行的方法链中的第 8 个方法?有没有办法在不修改这些方法的参数的情况下实现这一目标?
谢谢
如果您使用 DI 实例化服务依赖项,您可以通过 services.AddHttpContextAccessor()
注册 IHttpContextAccessor
并使用它来获取有关请求的信息:
public SomeService(IHttpContextAccessor contextAccessor)
{
_contextAccessor = contextAccessor;
}
public void SomeServiceMethod()
{
var auth = _contextAccessor.HttpContext.Request.Headers[HeaderNames.Authorization].ToString(); // possibly will need to remove scheme from the header
}
This particular case using JWT, there's no logged in user. The presence of valid JWT suffices.
假设您启用了 auth 中间件,如果请求能够到达 CreateUser
操作,则 [Authorize]
属性确保令牌有效。所以你不需要再做一次验证。
其次,您不应该将令牌向下传送到存储库。将 HTTP 和数据检索问题分开。
不“将参数向下传递 8 级”的解决方案是 use dependency injection 在整个应用程序中并让它跟踪依赖项。
要访问存储库中的当前用户,请创建一个公开用户的界面:
interface IPrincipalAccessor {
ClaimsPrincipal? Principal { get; }
}
然后用 IHttpContextAccessor
private class HttpPrincipalAccessor : IPrincipalAccessor
{
private IHttpContextAccessor _httpContextAccessor;
public HttpPrincipalAccessor(IHttpContextAccessor httpContextAccessor)
{
_httpContextAccessor = httpContextAccessor;
}
public ClaimsPrincipal? Principal => _httpContextAccessor?.HttpContext?.User;
}
您需要启用 IHttpAccessor
并在 DI:
services.AddHttpContextAccessor();
services.AddScoped<IPrincipalAccessor, HttpPrincipalAccessor>();
现在您可以在您的存储库中注入此接口并使用用户声明。回购不知道,也不关心用户来自哪里,它只需要知道当前用户。
class MyRepo
{
private IPrincipalAccessor _principalAccessor;
public MyRepo(IPrincipalAccessor principalAccessor)
{
_principalAccessor = principalAccessor;
}
Task Create(/* some parameters */)
{
var user = _principalAccessor.Principal;
if (user.HasClaim("eyes", "2"))
{
// user has two eyes
}
// ...
}
}
但是你的代码的问题是你没有使用依赖注入,所以你需要注入你的 repo,而不是 new
把它搞起来。