/// <summary> /// RefreshAccessTokenAsync /// </summary> /// <param name="apiClient"></param> /// <param name="endpointSettings"></param> /// <returns></returns> /// <exception cref="ApiException"></exception> public static async Task <bool> RefreshAccessTokenAsync(IApiClient apiClient, EndpointSettings?endpointSettings) { if (UserPreferences.AccessToken.IsNullOrEmpty()) { return(false); } JwtEndpointSetting jwtEndpoint = endpointSettings == null?apiClient.GetDefaultJwtEndpointSetting() : endpointSettings.JwtEndpoint; string accessTokenHashKey = SecurityUtil.GetHash(UserPreferences.AccessToken); //这个AccessToken不久前刷新过 if (!_requestLimiter.NoWaitLock(nameof(RefreshAccessTokenAsync), accessTokenHashKey, TimeSpan.FromSeconds(jwtEndpoint.RefreshIntervalSeconds))) { //可能已经有人在刷新,等他刷新完 if (!await _lastRefreshResultsAccessSemaphore.WaitAsync(TimeSpan.FromSeconds(10)).ConfigureAwait(false)) { //等待失败 BaseApplication.ExceptionHandler(ApiExceptions.TokenRefreshError(cause: "AccessToken 有人刷新过,等待获取结果失败。")); return(false); } try { if (_lastRefreshResults.TryGetValue(accessTokenHashKey, out bool lastRefreshResult)) { return(lastRefreshResult); } BaseApplication.ExceptionHandler(ApiExceptions.TokenRefreshError(cause: "AccessToken 有人刷新过,但结果获取为空。")); return(false); } finally { _lastRefreshResultsAccessSemaphore.Release(); } } //开始刷新,其他想取结果的人等着 await _lastRefreshResultsAccessSemaphore.WaitAsync().ConfigureAwait(false); try { if (UserPreferences.RefreshToken.IsNotNullOrEmpty()) { RefreshAccessTokenRequest refreshRequest = new RefreshAccessTokenRequest( jwtEndpoint.EndpointName !, jwtEndpoint.Version !, HttpMethod.Get, jwtEndpoint.ResourceName !, UserPreferences.AccessToken, UserPreferences.RefreshToken); AccessTokenResource?resource = await apiClient.GetFirstOrDefaultAsync(refreshRequest).ConfigureAwait(false); if (resource != null) { _lastRefreshResults.Clear(); _lastRefreshResults[accessTokenHashKey] = true; OnRefreshSucceed(resource); return(true); } } //刷新失败 _lastRefreshResults.Clear(); _lastRefreshResults[accessTokenHashKey] = false; OnRefreshFailed(); return(false); } catch { //刷新失败 _lastRefreshResults.Clear(); _lastRefreshResults[accessTokenHashKey] = false; OnRefreshFailed(); throw; } finally { _lastRefreshResultsAccessSemaphore.Release(); } }