一次刷新 accessToken 的最佳方法

Posted

技术标签:

【中文标题】一次刷新 accessToken 的最佳方法【英文标题】:Best way to refresh accessToken once 【发布时间】:2019-01-29 13:11:12 【问题描述】:

从我的 ASP.NET Core 应用程序中,我想使用一个由某种令牌身份验证保护的 API。 由于获取令牌的过程需要很长时间(而且我认为不必要地多次这样做是不好的设计)我想确保如果没有令牌或者它是过期了。

这是我的方法: 我创建了一个新服务并将其注册为单例

   services.AddSingleton<IService, Service>();

服务本身是这样的

public class Service : IService

    private object _lock = new object();
    private JwtSecurityToken _accessToken;

    public Service()
    
        GetNewToken();
    

    public async Task<object> GetSomething()
    
        EnsureAccessTokenValidity();
        //Do the api call with the token
    

    public async Task<object> GetSomethingDifferent()
    
        EnsureAccessTokenValidity();
        //Do the api call with the token
    

    private void EnsureAccessTokenValidity()
    

        if (_accessToken.ValidTo > DateTime.UtcNow) return;
        lock (_lock)
        
            if (_accessToken.ValidTo > DateTime.UtcNow) return;
            GetNewToken(); 
        
    

    private void GetNewToken()
    
        //Get a new _accessToken 
    

这似乎可行,但我认为应该有一种更优雅的方式来管理它。各位大佬是怎么处理这个问题的?

【问题讨论】:

【参考方案1】:

您可以为此使用缓存。将其策略的AbsoluteExpiration 设置为ValidTo(最好有一个小的偏移量),一旦过期,它将被自动驱逐。比如:

private readonly ObjectCache _cache = MemoryCache.Default;

public T GetToken()

    if (!_cache.Contains("token"))
    
        GetAndCacheNewToken();
    

    return _cache.Get("token") as T;


public void GetAndCacheNewToken()

    T token;

    // Get your token.

    _cache.Add(
        "token", 
        token, 
        new CacheItemPolicy() AbsoluteExpiration = token.ValidTo.AddSeconds(-1));

我将令牌的类型标记为T,因为我不知道它在您的应用中是什么类型。

【讨论】:

从某种意义上说,我认为这是一个糟糕的解决方案,因为它将缓存引入了等式,这带来了它自己的问题,如缓存失效。在这种情况下,它对管理访问令牌本身的生命周期的单例服务几乎没有任何改进......将令牌生命周期委托给具有绝对过期时间的缓存层也可能导致问题(如果令牌在缓存失效之前过期?) 它没有引入新的生命周期管理服务,而是利用了现有的缓存服务。其次,令牌在缓存使其失效之前不会过期,这就是绝对过期的目的,并且它还受到 1 秒(特定于实现的 tbh)偏移量的保护。 是的,但这假设在缓存过期和令牌过期之间的一秒钟内有一个请求进入。此外,如果多个请求遇到相同的过期缓存项,它们都将并行获取一个新令牌,这取决于发生的次数以及您的应用程序正在运行的实例数量,可以轻松取消不可扩展的身份提供程序。 .. 此外,它在您的应用程序中引入了静态上下文,这扼杀了对利用缓存的服务进行任何可重复测试的所有希望......【参考方案2】:

嘿@askingdumbquestions,欢迎加入社区

您最初的方法是有意义的,但有一些缺点:

    遇到过期令牌的请求会定期出现性能下降,因为它将在同一进程中获取。 由于可以并行处理请求 - 可能是多个请求遇到过期令牌并获取新令牌的情况。根据并行运行的请求数量,这很容易使您的身份验证服务速度变慢——这不是我们所希望的!是的:这可以通过一个简单的 Mutex 来解决,围绕 expiration 检查和获取令牌。这将导致许多锁定和任务相互等待,以及必须获取令牌的一个任务! (在获取令牌时,所有请求都将/必须被阻止)。

但还有另一种方法:您在第一次构造 Service 时获取您的令牌,然后启动一个异步任务,该任务在令牌到期前几分钟获取/刷新令牌!这将确保您始终准备好有效的令牌,并消除对昂贵且容易出错的线程同步的需求,并消除其他副设备必须获取令牌的请求的延迟峰值。

如果这有帮助或者您需要更详细的解释,请告诉我!

【讨论】:

以上是关于一次刷新 accessToken 的最佳方法的主要内容,如果未能解决你的问题,请参考以下文章

php微信开发-自动刷新accesstoken

如何使用refresh token

java微信的accesstoken怎么嫒缓竺小时更新

为啥要使用refresh token?为何会更安全?

用 WebView 中的事件刷新列表的最佳方法

tmp