【问题标题】:reuse token asp.net web api c#重用令牌 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 分钟,那么我会继续获取新令牌。您最有可能需要将令牌和到期时间存储在某个单例类中。你有依赖注入系统吗?

标签: c# asp.net asp.net-mvc asp.net-web-api


【解决方案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 SoftwareYou're probably still using HttpClient Wrong And It's Destabilizing Your Software 中详述的问题。更好的解决方案是使用Flurl,它会为您处理这些细节。

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

【讨论】:

  • 很好的答案,除了你的实现不是线程安全的。它将不必要地创建额外的令牌。请安全地添加线程,并且展示如何使用 TokenClient 类也是一个好主意,我会投票赞成。
  • 一个天真的问题,我如何测试它是否有效?使用邮递员在本地运行,它总是生成一个新的令牌。
  • @user2281858 你有没有像我说的那样用你的 DI 容器将这个类注册为单例?
  • 我想是的,让我用我所做的更新代码。
  • @mason 检查实现代码。
猜你喜欢
  • 2019-08-03
  • 1970-01-01
  • 2020-11-04
  • 2013-03-27
  • 2016-06-17
  • 1970-01-01
  • 2015-04-13
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多