Windows下如何在两个独立EXE进程间共享Azure Access Token并静默刷新?
解决方案
方法1:传递Refresh Token而非仅Access Token
Access Token有效期通常仅1小时,而Refresh Token可用于静默获取新的Access Token,无需用户交互。第一个EXE需同时获取并传递Refresh Token,第二个EXE用它刷新Token并填充本地缓存。
修改要点
- 第一个EXE登录后,保存
AuthenticationResult中的RefreshToken,并将其与Access Token、用户ID一起传递给第二个EXE - 第二个EXE收到后,优先用Refresh Token获取新Token:
' 第二个EXE新增RefreshToken属性 Private Shared _refreshToken As String Public Property RefreshToken As String Get Return _refreshToken End Get Set(ByVal value As String) _refreshToken = value End Set End Property ' 修改AcquireTokenAsync逻辑 Public Overrides Async Function AcquireTokenAsync(ByVal parameters As SqlAuthenticationParameters) As Task(Of SqlAuthenticationToken) Dim authContext As AuthenticationContext = New AuthenticationContext(parameters.Authority) authContext.CorrelationId = parameters.ConnectionId Dim result As AuthenticationResult ' 优先尝试用Refresh Token刷新 If Not String.IsNullOrEmpty(Me.RefreshToken) Then Try result = Await authContext.AcquireTokenByRefreshTokenAsync(Me.RefreshToken, _clientId, parameters.Resource) ' 更新本地Token、过期时间和新的Refresh Token Me.Token = result.AccessToken Me.Expire = result.ExpiresOn Me.RefreshToken = result.RefreshToken Return New SqlAuthenticationToken(result.AccessToken, result.ExpiresOn) Catch ex As Exception ' Refresh Token失效时再执行后续逻辑 End Try End If ' 检查传入的Access Token是否过期 If Not String.IsNullOrEmpty(Me.Token) AndAlso Me.Expire > DateTimeOffset.UtcNow.AddMinutes(5) Then Return New SqlAuthenticationToken(Me.Token, Me.Expire) End If ' 尝试静默获取Token(此时缓存已通过Refresh Token填充) Try result = Await authContext.AcquireTokenSilentAsync(parameters.Resource, _clientId) Me.Token = result.AccessToken Me.Expire = result.ExpiresOn Me.RefreshToken = result.RefreshToken Return New SqlAuthenticationToken(result.AccessToken, result.ExpiresOn) Catch ex As Exception Throw New InvalidOperationException("无法静默刷新Token,请重新登录") End Try End Function
方法2:序列化并共享ADAL Token缓存
ADAL的AuthenticationContext.TokenCache可序列化为二进制数据,传递给第二个EXE后反序列化加载,这样AcquireTokenSilentAsync就能直接从缓存读取可用的Token或Refresh Token,自动完成刷新。
实现步骤
- 第一个EXE登录后,序列化TokenCache并编码为Base64字符串:
' 第一个EXE中获取缓存并序列化 Dim cacheBytes As Byte() = authContext.TokenCache.Serialize() Dim cacheBase64 As String = Convert.ToBase64String(cacheBytes) ' 将cacheBase64作为命令行参数传递给第二个EXE
- 第二个EXE初始化
AuthenticationContext后,加载缓存:
' 第二个EXE中新增CacheBase64属性 Private Shared _cacheBase64 As String Public Property CacheBase64 As String Get Return _cacheBase64 End Get Set(ByVal value As String) _cacheBase64 = value End Set End Property ' 修改AcquireTokenAsync逻辑,先加载缓存 Public Overrides Async Function AcquireTokenAsync(ByVal parameters As SqlAuthenticationParameters) As Task(Of SqlAuthenticationToken) Dim authContext As AuthenticationContext = New AuthenticationContext(parameters.Authority) authContext.CorrelationId = parameters.ConnectionId ' 加载共享的Token缓存 If Not String.IsNullOrEmpty(Me.CacheBase64) Then Dim cacheBytes As Byte() = Convert.FromBase64String(Me.CacheBase64) authContext.TokenCache.Deserialize(cacheBytes) End If ' 直接调用AcquireTokenSilentAsync,缓存会自动处理刷新 Try Dim result = Await authContext.AcquireTokenSilentAsync(parameters.Resource, _clientId) Return New SqlAuthenticationToken(result.AccessToken, result.ExpiresOn) Catch ex As Exception Throw New InvalidOperationException("无法静默刷新Token,请重新登录") End Try End Function
方法3:使用加密共享存储缓存Token
将TokenCache序列化后加密保存到用户目录下的文件或注册表中,第二个EXE启动时读取并解密加载。这种方式比命令行传递更安全,适合长期共享场景。
关键注意事项
- 安全性:Refresh Token和TokenCache包含敏感信息,传递或存储时必须加密(比如使用DPAPI加密),防止泄露
- Refresh Token有效期:Azure AD的Refresh Token默认有效期90天,过期后仍需交互式登录,可在第一个EXE中定期刷新Refresh Token延长有效期
- 库迁移:ADAL已停止维护,建议迁移到MSAL(Microsoft Authentication Library),MSAL提供更灵活的Token缓存共享机制,支持跨进程、跨设备的缓存同步
内容的提问来源于stack exchange,提问作者Bruce Wayne
相关产品推荐
相关产品推荐

