当前位置: 首页 > 知识库问答 >
问题:

我可以强制注销JWT令牌或使其过期吗?

夹谷星河
2023-03-14

对于身份验证,目前我们使用JWT,因此一旦创建了令牌,它就会在整个生命周期内创建,如果我们设置了时间过期,令牌将过期。

有没有办法使令牌过期?

单击注销按钮时,我需要销毁令牌。

我正在使用ASP. NET Core WebAPI。

共有2个答案

茹展鹏
2023-03-14

实际上,最好的注销方法就是从客户端删除令牌。您可以缩短令牌的生存期(5-15分钟),并实现刷新令牌以增加安全性。在这种情况下,攻击者对您的JWT进行操作的可能性较小

曹茂材
2023-03-14

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

我们将从界面开始:

public interface ITokenManager
{
    Task<bool> IsCurrentActiveToken();
    Task DeactivateCurrentAsync();
    Task<bool> IsActiveAsync(string token);
    Task DeactivateAsync(string token);
}

并对其实现进行处理,其基本思想是只跟踪停用的令牌,并在不再需要时将其从缓存中删除(也就是说当过期时间过去时)——它们无论如何都将不再有效。

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

如您所见,有两个助手方法将使用当前的HttpContext,以使事情变得更加简单。

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

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

最后,让我们实现一个用于取消令牌的endpoint来结束我们的旅程:

[HttpPost("tokens/cancel")]
public async Task<IActionResult> CancelAccessToken()
{
    await _tokenManager.DeactivateCurrentAsync();
 
    return NoContent();
}

当然,我们可以通过通过URL传递令牌或一次取消所有现有的用户令牌(这需要额外的实现来跟踪它们)来使其更加复杂,但这是一个基本的示例。

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

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

并在appsettings中为Redis提供配置。json文件:

"redis": {
  "connectionString": "localhost"
}

现在试着运行应用程序并调用令牌取消(sic)endpoint–就是这样。

 类似资料:
  • 当用户单击注销按钮时,如何使JWT令牌无效?我做了一些研究,但没有找到任何好的实现。

  • 嗨,我正在创建使用 REST API endpoint与服务器端通信的移动本机应用程序。 我以前有开发本机客户端的经验,但我将简单的令牌(随机生成的字符串)存储在存储用户信息的同一表中的数据库中。所以它就像浏览器中使用的会话,但每个请求的标头中都有令牌,而不是 cookie。 最近我发现了JWT令牌。这似乎是保护私有endpoint的好方法。您可以从移动客户端请求令牌,前提是您通过登录并获得生成的

  • 我们有一个带有Angular 2的Spring启动应用程序,对于身份验证,我们使用JWT。我遇到了一个问题——即使令牌已经过期,然后注销并再次登录,过期的JWT令牌仍然在请求标头上可用。因此后端仍然验证旧的JWT令牌,而不是新令牌。我需要清除浏览器缓存使其工作。 我看到令牌存储在Sessionstore中,下面的操作也是为了在上清除令牌 但这也不是清除旧令牌。我可以做些什么来从浏览器中清除令牌?

  • 问题内容: 我在hapijs中使用jwt插件和策略。 我可以在登录用户时创建jwt令牌,并通过’jwt’策略使用同一令牌对其他API进行身份验证。 我将令牌设置为cookie,其中是令牌名称。另外,我没有将这些令牌保存在数据库中。 但是,注销时如何销毁jwt令牌? 请提出一种方法。 问题答案: JWT存储在浏览器中,因此删除令牌以删除客户端的cookie 如果您还需要在令牌到期之前从服务器端使令牌

  • 我在springboot中用jwt令牌开发了一个oauth2服务器,我在注销时遇到了困难http://www.baeldung.com/spring-security-oauth-revoke-tokens 注销后,如果在头中提供令牌并点击/user,则它将提供所有用户信息,而应该抛出并错误地表示用户已注销

  • 我使用了一个JWT(Json Web令牌),它在负载中有一个刷新令牌(GUID)。通常,我使用Firebase JWT创建/编码和解码JWT。 我想在PHP中解码一个过期的JWT,然后使用其负载中的刷新令牌创建一个新的JWT(只要刷新令牌仍然有效)。如果我用Firebase解码JWT,它会抛出一个异常(过期),并且不会返回解码后的令牌。 如何安全地解码过期的JWT并访问它的有效负载?我可以只捕获过