WPF中使用Microsoft Graph API延长过期OAuth 2.0访问令牌方法
问题描述
- 当前使用Microsoft Graph API的OAuth 2.0客户端凭证模式(client_credentials)生成访问令牌,令牌默认1小时后过期
- 令牌获取地址:
https://login.microsoftonline.com/{Tenant ID} - 请求参数:
{ grant_type: "client_credentials", client_id: APP_ID, client_secret: APP_PASSWORD, scope: "https://graph.microsoft.com/.default" }
- 现有实现中,调用Graph API从AD拉取用户详情前已添加递归重试逻辑,现在需要在C#中实现延长访问令牌的有效时长,避免频繁过期导致的请求失败
核心说明
首先明确:OAuth 2.0访问令牌本身的过期时间无法在生成后修改,只能通过配置Azure AD应用的令牌生命周期延长最大允许时长,同时在C#代码中通过令牌缓存与自动刷新机制确保使用的始终是有效令牌。
解决方案
1. 在Azure门户配置令牌最大过期时长
客户端凭证模式的令牌默认过期时间为1小时,Azure AD允许将其最长设置为24小时,步骤如下:
- 登录Azure门户,找到对应的应用注册
- 进入「令牌配置」选项卡,点击「添加配置」
- 选择「访问令牌」,设置「过期时间(分钟)」(最大1440分钟,即24小时),保存配置
2. 在C#中用MSAL库自动管理令牌(推荐)
不要手动调用令牌获取接口,使用Microsoft.Identity.Client(MSAL)库来处理令牌的获取、缓存和自动刷新,示例代码如下:
首先安装NuGet包:Microsoft.Identity.Client
然后实现令牌管理类:
using Microsoft.Identity.Client; public class TokenManager { private readonly IConfidentialClientApplication _clientApp; private readonly string[] _scopes = new[] { "https://graph.microsoft.com/.default" }; public TokenManager(string tenantId, string clientId, string clientSecret) { _clientApp = ConfidentialClientApplicationBuilder .Create(clientId) .WithClientSecret(clientSecret) .WithAuthority(new Uri($"https://login.microsoftonline.com/{tenantId}")) .Build(); } public async Task<string> GetAccessTokenAsync() { // 先尝试从缓存获取令牌 var accounts = await _clientApp.GetAccountsAsync(); AuthenticationResult result; try { result = await _clientApp.AcquireTokenSilent(_scopes, accounts.FirstOrDefault()) .ExecuteAsync(); } catch (MsalUiRequiredException) { // 缓存无有效令牌,重新获取 result = await _clientApp.AcquireTokenForClient(_scopes) .ExecuteAsync(); } return result.AccessToken; } }
3. 改造现有数据库访问代码
将原有直接使用_systemEnvironment.AzureConnectionToken的逻辑,替换为从TokenManager获取有效令牌,确保每次使用的都是未过期的令牌:
// 建议将TokenManager以单例方式注入,避免重复初始化 var tokenManager = new TokenManager(_systemEnvironment.TenantId, _systemEnvironment.AppId, _systemEnvironment.AppPassword); public async Task<string> SelectInterfaceEndPointAsync(Guid? franchiseRegionUid) { var endPoint = string.Empty; try { using (var cn = new SqlConnection(_systemEnvironment.CommonConnectionString)) { if (_systemEnvironment.IsLiveCommonServer) { // 实时获取有效令牌 cn.AccessToken = await tokenManager.GetAccessTokenAsync(); } using (var cmd = new SqlCommand("FranchiseRegion_SelectEndPoint", cn)) { cmd.CommandType = CommandType.StoredProcedure; if (franchiseRegionUid != null) cmd.Parameters.Add("@FranchiseRegionUid", SqlDbType.UniqueIdentifier).Value = franchiseRegionUid; await cn.OpenAsync(); using (SqlDataReader reader = await cmd.ExecuteReaderAsync()) { if (await reader.ReadAsync()) { endPoint = General.DbNullString(reader["InterfaceEndPoint"].ToString()); } } } } return endPoint; } catch (Exception ex) { _logMessage.Log(_project, _module, "SelectInterfaceEndPoint", EventLogEntryType.Error, ex, string.Empty, _userId); return endPoint; } }
补充说明
- 不要尝试手动延长已生成令牌的过期时间,这不符合OAuth 2.0规范,Azure AD也不支持修改已签发令牌的有效期
- MSAL库会自动处理令牌缓存,只有当缓存中的令牌即将过期(或已过期)时才会重新请求新令牌,有效减少不必要的请求
- 若必须使用手动令牌获取逻辑,需自行维护令牌的过期时间,在每次使用前检查是否即将过期,若过期则重新请求
内容的提问来源于stack exchange,提问作者Subasri M
相关产品推荐
相关产品推荐

