JWT 令牌:注销 JWT 令牌

iBa*_*ala 7 .net api core jwt jwt-auth

目前我们正在使用 JWT 进行身份验证,因此一旦创建令牌,它就是终身的,如果我们设置时间过期,令牌将过期。有什么办法可以使令牌过期吗?单击注销按钮时,我需要销毁令牌。asp.net 核心,web api。

iBa*_*ala 10

我认为取消 JWT 是处理注销的最佳方式。Piotr 在他的博客中解释得很好:取消 JWT 令牌

\n
\n

我们将从界面开始:

\n
public interface ITokenManager\n{\n    Task<bool> IsCurrentActiveToken();\n    Task DeactivateCurrentAsync();\n    Task<bool> IsActiveAsync(string token);\n    Task DeactivateAsync(string token);\n}\n
Run Code Online (Sandbox Code Playgroud)\n

并处理其实现,其中基本思想是仅跟踪已停用的令牌,并在不再需要时将它们从缓存中删除(意味着当到期时间过去时)\xe2\x80\x93 它们将不再\n无论如何有效。

\n
public class TokenManager : ITokenManager\n{\n    private readonly IDistributedCache _cache;\n    private readonly IHttpContextAccessor _httpContextAccessor;\n    private readonly IOptions<JwtOptions> _jwtOptions;\n \n    public TokenManager(IDistributedCache cache,\n            IHttpContextAccessor httpContextAccessor,\n            IOptions<JwtOptions> jwtOptions\n        )\n    {\n        _cache = cache;\n        _httpContextAccessor = httpContextAccessor;\n        _jwtOptions = jwtOptions;\n    }\n \n    public async Task<bool> IsCurrentActiveToken()\n        => await IsActiveAsync(GetCurrentAsync());\n \n    public async Task DeactivateCurrentAsync()\n        => await DeactivateAsync(GetCurrentAsync());\n \n    public async Task<bool> IsActiveAsync(string token)\n        => await _cache.GetStringAsync(GetKey(token)) == null;\n \n    public async Task DeactivateAsync(string token)\n        => await _cache.SetStringAsync(GetKey(token),\n            " ", new DistributedCacheEntryOptions\n            {\n                AbsoluteExpirationRelativeToNow =\n                    TimeSpan.FromMinutes(_jwtOptions.Value.ExpiryMinutes)\n            });\n \n    private string GetCurrentAsync()\n    {\n        var authorizationHeader = _httpContextAccessor\n            .HttpContext.Request.Headers["authorization"];\n \n        return authorizationHeader == StringValues.Empty\n            ? string.Empty\n            : authorizationHeader.Single().Split(" ").Last();\n    }\n    \n    private static string GetKey(string token)\n        => $"tokens:{token}:deactivated";\n}\n
Run Code Online (Sandbox Code Playgroud)\n

正如您所看到的,有 2 个辅助方法将使用当前\nHttpContext 以使事情变得更加简单。

\n

接下来,让\xe2\x80\x99s 创建一个中间件来检查令牌是否已停用。这就是为什么我们应该将它们保存在缓存中的原因\n\xe2\x80\x93 每个请求都会访问数据库,否则可能迟早会杀死\n你的应用程序(或者至少让它变得非常非常慢):

\n
public class TokenManagerMiddleware : IMiddleware\n{\n    private readonly ITokenManager _tokenManager;\n \n    public TokenManagerMiddleware(ITokenManager tokenManager)\n    {\n        _tokenManager = tokenManager;\n    }\n    \n    public async Task InvokeAsync(HttpContext context, RequestDelegate next)\n    {\n        if (await _tokenManager.IsCurrentActiveToken())\n        {\n            await next(context);\n            \n            return;\n        }\n        context.Response.StatusCode = (int) HttpStatusCode.Unauthorized;\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

最终,让 xe2x80x99s 通过实现取消令牌的端点来结束我们的旅程:

\n
[HttpPost("tokens/cancel")]\npublic async Task<IActionResult> CancelAccessToken()\n{\n    await _tokenManager.DeactivateCurrentAsync();\n \n    return NoContent();\n}\n
Run Code Online (Sandbox Code Playgroud)\n

当然,我们可以通过 URL 传递令牌\n或通过立即取消所有现有用户令牌\n(这将需要额外的实现来跟踪\n它们)来使其变得更加复杂,但这只是一个可以正常工作的基本示例。

\n

确保您将在容器中注册\n所需的依赖项并配置中间件:

\n
public void ConfigureServices(IServiceCollection services)\n{\n    ...\n    services.AddTransient<TokenManagerMiddleware>();\n    services.AddTransient<ITokenManager, Services.TokenManager>();\n    services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();\n    services.AddDistributedRedisCache(r => { r.Configuration = Configuration["redis:connectionString"]; \n    ...\n}\n \npublic void Configure(IApplicationBuilder app, IHostingEnvironment env,\n    ILoggerFactory loggerFactory)\n{\n    ...\n    app.UseAuthentication();\n    app.UseMiddleware<TokenManagerMiddleware>();\n    app.UseMvc();\n}\n
Run Code Online (Sandbox Code Playgroud)\n

并在 appsettings.json 文件中提供 Redis 的配置:

\n
"redis": {\n  "connectionString": "localhost"\n}\n
Run Code Online (Sandbox Code Playgroud)\n

现在尝试运行应用程序并调用令牌取消[原文如此]\n端点\xe2\x80\x93,\xe2\x80\x99s它。

\n
\n