iBa*_*ala 10
我认为取消 JWT 是处理注销的最佳方式。Piotr 在他的博客中解释得很好:取消 JWT 令牌
\n\n\n我们将从界面开始:
\nRun Code Online (Sandbox Code Playgroud)\npublic interface ITokenManager\n{\n Task<bool> IsCurrentActiveToken();\n Task DeactivateCurrentAsync();\n Task<bool> IsActiveAsync(string token);\n Task DeactivateAsync(string token);\n}\n并处理其实现,其中基本思想是仅跟踪已停用的令牌,并在不再需要时将它们从缓存中删除(意味着当到期时间过去时)\xe2\x80\x93 它们将不再\n无论如何有效。
\nRun Code Online (Sandbox Code Playgroud)\npublic 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正如您所看到的,有 2 个辅助方法将使用当前\nHttpContext 以使事情变得更加简单。
\n接下来,让\xe2\x80\x99s 创建一个中间件来检查令牌是否已停用。这就是为什么我们应该将它们保存在缓存中的原因\n\xe2\x80\x93 每个请求都会访问数据库,否则可能迟早会杀死\n你的应用程序(或者至少让它变得非常非常慢):
\nRun Code Online (Sandbox Code Playgroud)\npublic 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最终,让 xe2x80x99s 通过实现取消令牌的端点来结束我们的旅程:
\nRun Code Online (Sandbox Code Playgroud)\n[HttpPost("tokens/cancel")]\npublic async Task<IActionResult> CancelAccessToken()\n{\n await _tokenManager.DeactivateCurrentAsync();\n \n return NoContent();\n}\n当然,我们可以通过 URL 传递令牌\n或通过立即取消所有现有用户令牌\n(这将需要额外的实现来跟踪\n它们)来使其变得更加复杂,但这只是一个可以正常工作的基本示例。
\n确保您将在容器中注册\n所需的依赖项并配置中间件:
\nRun Code Online (Sandbox Code Playgroud)\npublic 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并在 appsettings.json 文件中提供 Redis 的配置:
\nRun Code Online (Sandbox Code Playgroud)\n"redis": {\n "connectionString": "localhost"\n}\n现在尝试运行应用程序并调用令牌取消[原文如此]\n端点\xe2\x80\x93,\xe2\x80\x99s它。
\n
| 归档时间: |
|
| 查看次数: |
9762 次 |
| 最近记录: |