【发布时间】:2015-12-12 05:11:22
【问题描述】:
我已经按照 Microsoft 的 Hello Key Vault 示例应用程序中的示例在我的 ASP.Net MVC Web 应用程序上设置了 Azure Keyvault。
默认情况下,Azure KeyVault (Active Directory) AuthenticationResult 的有效期为一小时。因此,一小时后,您必须获得一个新的身份验证令牌。 KeyVault 在获得我的第一个 AuthenticationResult 令牌后的第一个小时内按预期工作,但在 1 小时到期后,它无法获得新令牌。
不幸的是,我在生产环境中遇到了故障才意识到这一点,因为我从未在开发中测试超过一小时。
无论如何,经过两天多的尝试找出我的 keyvault 代码出了什么问题,我想出了一个解决方案来解决我的所有问题 - 删除异步代码 - 但它感觉非常糟糕。我想知道为什么它一开始就不起作用。
我的代码如下所示:
public AzureEncryptionProvider() //class constructor
{
_keyVaultClient = new KeyVaultClient(GetAccessToken);
_keyBundle = _keyVaultClient
.GetKeyAsync(_keyVaultUrl, _keyVaultEncryptionKeyName)
.GetAwaiter().GetResult();
}
private static readonly string _keyVaultAuthClientId =
ConfigurationManager.AppSettings["KeyVaultAuthClientId"];
private static readonly string _keyVaultAuthClientSecret =
ConfigurationManager.AppSettings["KeyVaultAuthClientSecret"];
private static readonly string _keyVaultEncryptionKeyName =
ConfigurationManager.AppSettings["KeyVaultEncryptionKeyName"];
private static readonly string _keyVaultUrl =
ConfigurationManager.AppSettings["KeyVaultUrl"];
private readonly KeyBundle _keyBundle;
private readonly KeyVaultClient _keyVaultClient;
private static async Task<string> GetAccessToken(
string authority, string resource, string scope)
{
var clientCredential = new ClientCredential(
_keyVaultAuthClientId,
_keyVaultAuthClientSecret);
var context = new AuthenticationContext(
authority,
TokenCache.DefaultShared);
var result = context.AcquireToken(resource, clientCredential);
return result.AccessToken;
}
GetAccessToken 方法签名必须是异步的才能传递给新的 KeyVaultClient 构造函数,所以我将签名保留为异步,但我删除了 await 关键字。
使用 await 关键字(应该是这样,并且在示例中):
private static async Task<string> GetAccessToken(string authority, string resource, string scope)
{
var clientCredential = new ClientCredential(_keyVaultAuthClientId, _keyVaultAuthClientSecret);
var context = new AuthenticationContext(authority, null);
var result = await context.AcquireTokenAsync(resource, clientCredential);
return result.AccessToken;
}
程序在我第一次运行时运行良好。一个小时后,AcquireTokenAsync 返回相同的原始身份验证令牌,这很棒。但是一旦令牌过期,AcquiteTokenAsync 应该会获得一个具有新过期日期的新令牌。它没有 - 应用程序只是挂起。没有返回错误,什么都没有。
所以调用 AcquireToken 而不是 AcquireTokenAsync 可以解决问题,但我不知道为什么。您还会注意到,我在示例代码中使用异步将“null”而不是“TokenCache.DefaultShared”传递到 AuthenticationContext 构造函数中。这是为了强制令牌立即过期,而不是在一小时后过期。否则,您必须等待一个小时才能重现该行为。
我能够在一个全新的 MVC 项目中再次重现这一点,所以我认为这与我的特定项目无关。任何见解将不胜感激。但现在,我只是不使用异步。
【问题讨论】:
-
要重现该行为,您还可以调用
context.TokenCache.Clear()而不是将null传递给构造函数。 -
嗨,肖恩,我正在使用 Azure SKD 2.7。而且我可以使用 context.TokenCache.Clear() 成功重现我的问题,而不是将 null 传递给构造函数。您也是正确的,问题是 AcquireTokenAsync() 一旦原始令牌过期就会挂起,解决方法是使用非异步方法。我将在下面尝试您的解决方案,看看它是否能解决我的问题。
-
这里要注意的另一件事是,在 Azure 网站上,这仅在 Always On 为真时发生 - 这意味着如果允许 IIS 关闭该网站,则该网站将重置并在该网站之后再次工作旋转回来。然后它会在运行一个小时后再次停止工作。
-
是的,我不在乎令牌是否实际过期。我只想每次都强制获得一个新的,因为在请求第二个令牌期间发生故障。
-
在我的生产环境中,我使用依赖注入,但是我能够在没有 DI 的全新 MVC 项目中重现这一点。我通过简单地创建类的实例并调用加密方法在控制器 ActionResult 方法中使用它。感谢您在这方面的帮助 - 我真的很想知道为什么这不起作用。我不介意使用非异步方法,我只是不明白为什么异步不起作用。
标签: c# asp.net azure async-await azure-active-directory