You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Web API C# 如何复用已生成的Token用于后续API调用

C# 实现Token复用的具体方案

1. 定义Token响应结构,反序列化返回结果

首先OAuth2密码模式返回的响应通常包含access_token、expires_in(有效时长,单位秒)、token_type等字段,你需要先将返回的字符串反序列化为强类型对象:

// 安装NuGet包:System.Text.Json 或 Newtonsoft.Json均可,以下用System.Text.Json为例
public class TokenResponse
{
    [JsonPropertyName("access_token")]
    public string AccessToken { get; set; }
    
    [JsonPropertyName("expires_in")]
    public int ExpiresIn { get; set; }
    
    [JsonPropertyName("token_type")]
    public string TokenType { get; set; }
    
    [JsonPropertyName("refresh_token")]
    public string RefreshToken { get; set; }

    // 缓存用:记录token的实际过期时间,提前30秒过期避免边缘时间失效
    public DateTime ExpireTime { get; set; }
}

2. 封装Token管理类,实现缓存与自动刷新

用线程安全的方式缓存有效Token,避免每次API请求都重复申请Token:

public class TokenManager
{
    private readonly string _tokenUrl;
    private readonly string _user;
    private readonly string _pwd;
    private readonly string _clientId;
    private readonly string _clientSecret;
    private static TokenResponse _cachedToken;
    private static readonly object _lockObj = new object();

    public TokenManager(string tokenUrl, string user, string pwd, string clientId, string clientSecret)
    {
        _tokenUrl = tokenUrl;
        _user = user;
        _pwd = pwd;
        _clientId = clientId;
        _clientSecret = clientSecret;
    }

    // 对外暴露的获取有效Token的方法
    public string GetValidToken()
    {
        lock (_lockObj)
        {
            // 缓存的Token还没过期,直接返回
            if (_cachedToken != null && _cachedToken.ExpireTime > DateTime.Now)
            {
                return _cachedToken.AccessToken;
            }

            // 无有效Token,重新申请
            _cachedToken = RequestNewToken();
            return _cachedToken.AccessToken;
        }
    }

    // 内部调用的申请新Token的方法
    private TokenResponse RequestNewToken()
    {
        using (var client = new HttpClient())
        {
            var postData = new List<KeyValuePair<string, string>>
            {
                new("username", _user),
                new("password", _pwd),
                new("grant_type", "password"),
                new("client_id", _clientId),
                new("client_secret", _clientSecret)
            };

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

            // 建议生产环境改成异步await写法,避免阻塞
            var response = client.PostAsync(_tokenUrl, content).Result;
            response.EnsureSuccessStatusCode();
            var tokenStr = response.Content.ReadAsStringAsync().Result;
            var token = JsonSerializer.Deserialize<TokenResponse>(tokenStr);
            
            // 计算实际过期时间
            token.ExpireTime = DateTime.Now.AddSeconds(token.ExpiresIn - 30);
            return token;
        }
    }
}

3. 复用Token发起后续API请求

拿到有效Token后,将其添加到请求的Authorization头中即可调用其他业务接口:

// 初始化TokenManager(建议单例注入使用)
var tokenManager = new TokenManager("你的token地址", "用户名", "密码", "clientId", "clientSecret");

// 调用业务API示例
public async Task<string> CallBusinessApi(string apiUrl)
{
    // 自动获取有效Token,无需关心是否过期
    var accessToken = tokenManager.GetValidToken();
    
    using (var client = new HttpClient())
    {
        // 把Token加到请求头
        client.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", accessToken);
        
        var response = await client.GetAsync(apiUrl);
        response.EnsureSuccessStatusCode();
        return await response.Content.ReadAsStringAsync();
    }
}

注意事项

  • 生产环境建议不要每次都new HttpClient,可通过IHttpClientFactory注入复用HttpClient实例,避免端口耗尽问题
  • 如果接口支持refresh_token,建议Token过期时优先用refresh_token刷新,避免频繁传递用户名密码
  • 并发量高的场景可以用SemaphoreSlim代替lock做异步锁,配合异步方法使用性能更好

内容的提问来源于stack exchange,提问作者user2281858

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.27 17:24:03