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
相关产品推荐
相关产品推荐

