如何跟踪我的 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 把它搞起来。