重用令牌 asp.net web api c#

Posted

技术标签:

【中文标题】重用令牌 asp.net web api c#【英文标题】:reuse token asp.net web api c# 【发布时间】:2021-12-17 09:49:10 【问题描述】:

我有以下代码来生成令牌。

如果令牌已经生成,我如何确保重新使用它。该令牌用于后续 API 调用。

 using (var client = new HttpClient())

    var postData = new List<KeyValuePair<string, string>>();
    postData.Add(new KeyValuePair<string, string>("username", _user));
    postData.Add(new KeyValuePair<string, string>("password", _pwd));
    postData.Add(new KeyValuePair<string, string>("grant_type", "password"));
    postData.Add(new KeyValuePair<string, string>("client_id", _clientId));
    postData.Add(new KeyValuePair<string, string>("client_secret", _clientSecret));

    HttpContent content = new FormUrlEncodedContent(postData);
    content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");

    var responseResult = client.PostAsync(_tokenUrl, content).Result;

    return responseResult.Content.ReadAsStringAsync().Result;

【问题讨论】:

这能回答你的问题吗? Setting Authorization Header of HttpClient 我想检查一个令牌的有效性。 创建另一个 HttpClient 实例以进行 API 调用并设置 httpClient.DefaultRequestHeaders.Authorization,如我的第一条评论所示。通过该 httpclient 进行的所有后续 API 调用都将包含该令牌。 我们需要更多详细信息来指导您找到合适的解决方案。令牌的生命周期是多少?多长时间好用? 上述代码每次调用都会获取一个新的token。一旦获得令牌,您选择做什么决定了它是否被重用。你没有表现出来。所以 3600 秒 - 那是 1 小时。所以我要做的是存储令牌和令牌预计到期的日期时间。在每次通话时,我都会检查存储的日期时间。如果在到期时间前 2 分钟,那么我会继续获取新令牌。您最有可能需要将令牌和到期时间存储在某个单例类中。你有依赖注入系统吗? 【参考方案1】:

令牌有效期为 1 小时。因此,您只需将其存储 1 小时即可获得新的令牌。理想情况下,您会在时间限制结束前几分钟获得一个令牌,以减少您使用无效令牌的机会。

所以,让我们创建一个负责获取和缓存令牌的类。此类需要在您的 Dependency Injection 容器中注册为单例,以便只有一个实例。否则,您将一直不必要地获得新令牌。我不知道您使用的是什么依赖注入容器,所以您必须研究如何将我们的 TokenClient 类注册为单例。

我们将在 DateTime 字段中捕获我们获得令牌的时间,并在字段中捕获令牌本身。

public class TokenClient

    readonly IHttpClientFactory _httpClientFactory;

    string _cachedToken;

    DateTime _tokenRetrievalTime;
    

    public TokenClient(IHttpClientFactory httpClientFactory)
    
        _httpClientFactory = httpClientFactory;
    

    public async Task<string> GetToken()
    
        if (!string.IsNullOrEmpty(_cachedToken) && _tokenRetrievalTime.AddMinutes(55) > DateTime.Now)
        
            _cachedToken = await GetTokenFromServer();
            _tokenRetrievalTime = DateTime.Now;
            return _cachedToken;
        
        else
        
            return _cachedToken;
        
    

    async Task<string> GetTokenFromServer()
    
        var postData = new List<KeyValuePair<string, string>>();
 
        postData.Add(new KeyValuePair<string, string>("grant_type", "password"));
        postData.Add(new KeyValuePair<string, string>("client_id", _clientId));
        postData.Add(new KeyValuePair<string, string>("client_secret", _clientSecret));

        HttpContent content = new FormUrlEncodedContent(postData);
        content.Headers.ContentType = new MediaTypeHeaderValue("application/x-www-form-urlencoded");
        var client = _httpClientFactory.CreateClient();
        var responseResult = await client.PostAsync(_tokenUrl, content);

        string token = await responseResult.Content.ReadAsStringAsync();
        return token;
    

除了缓存令牌之外,我在这里还做了一些不同的事情。我正在使用 IHttpClientFactory 来获取 HttpClient 的实例,以避免You're Using HttpClient Wrong And It's Destablizing Your Software 和You're probably still using HttpClient Wrong And It's Destabilizing Your Software 中详述的问题。更好的解决方案是使用Flurl,它会为您处理这些细节。

与您的代码相比,我更改的另一件事是我正在正确等待返回任务的调用。这可以防止代码死锁,并有助于保持其高效运行。有关这方面的更多信息,请参阅 Async Await Best Practices 和 8 Await Async Mistakes You Should Avoid。

【讨论】:

很好的答案,除了你的实现不是线程安全的。它将不必要地创建额外的令牌。请安全地添加线程,并且展示如何使用 TokenClient 类也是一个好主意,我会投票赞成。 一个天真的问题,我如何测试它是否有效?使用邮递员在本地运行,它总是生成一个新的令牌。 @user2281858 你有没有像我说的那样用你的 DI 容器将这个类注册为单例? 我想是的,让我用我所做的更新代码。 @mason 检查实现代码。

以上是关于重用令牌 asp.net web api c#的主要内容,如果未能解决你的问题,请参考以下文章

ASP.NET Web API 授权令牌提前到期

了解 ASP.NET(MVC、Web API)中的令牌生成/验证

web api - asp.net 身份令牌即使对于后续请求也会过期

如何使用 Web Api Asp.Net Core 实现基于声明的授权?

ASP .NET Web Api OAuth 刷新令牌过期时间

使用 AspNetUserTokens 表在 ASP.NET Core Web Api 中存储刷新令牌