对于身份验证,目前我们使用JWT,因此一旦创建了令牌,它就会在整个生命周期内创建,如果我们设置了时间过期,令牌将过期。
有没有办法使令牌过期?
单击注销按钮时,我需要销毁令牌。
我正在使用ASP. NET Core WebAPI。
实际上,最好的注销方法就是从客户端删除令牌。您可以缩短令牌的生存期(5-15分钟),并实现刷新令牌以增加安全性。在这种情况下,攻击者对您的JWT进行操作的可能性较小
我认为取消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并访问它的有效负载?我可以只捕获过