使用Azure AD时,在Asp.Net MVC中处理令牌超时
本文关键字:MVC 处理 令牌 超时 Net Asp AD Azure 使用 | 更新日期: 2023-09-27 18:20:04
这更多的是一个设计/方法问题。。。
我想我错过了什么。我们正在构建一个Asp.Net MVC 5 web应用程序,并使用以下场景使用Azure AD保护它:
https://azure.microsoft.com/en-us/documentation/articles/active-directory-authentication-scenarios/#web-浏览器到web应用程序
https://github.com/Azure-Samples/active-directory-dotnet-webapp-openidconnect
令牌/cookie是绝对过期的,在一小时后过期。那么,这对用户体验有什么影响呢?不管怎样,他们每小时都必须重新登录?在我们的测试中,当用户过期时,浏览器会重定向回AD,并提示用户输入凭据。当然,这会中断我们加载部分视图的任何AJAX调用,因此我们的DevExpress控件都不稳定。
基于对这篇SO帖子的回应:通过ADAL JavaScript Ajax和KnockoutJs 的MVC AD Azure刷新令牌
我看到的是意料之中的事?在我看来,对于用户全天登录并工作的云托管业务线应用程序来说,这似乎不是一个非常可行的解决方案。
我是不是错过了什么?还是这不是商业应用程序的理想场景?
我们面临着一系列类似的问题,以及如何在会话超时(60分钟)如此低的web应用程序中使用带有ASP.NET MVC的Azure AD的相同想法。
我们提出的解决方案似乎是有效的(尽管测试有限),就是在页面上有一个iFrame,我们每5分钟刷新一次。
<iframe sandbox="allow-same-origin allow-scripts allow-popups allow-forms" id="refreshAuthenticationIframe" src="@Url.Action("CheckSessionTimeout", "Home", new { area = "" })" style="display:none;"></iframe>
"CheckSessionTimeout"页面基本上是空白的。
在整个应用程序引用的Javascript文件中,我们有:
var pageLoadTime = moment();
setInterval(refreshAuthenticationCookies, 1000);
function refreshAuthenticationCookies() {
if (moment().diff(pageLoadTime, "seconds") > 300) {
document.getElementById("refreshAuthenticationIframe").contentDocument.location = "/Home/ForceSessionRefresh";
pageLoadTime = moment();
}
}
(注意:moment是我们使用的JS日期/时间库)。在家庭控制器上,我们有:
public ActionResult CheckSessionTimeout() => View();
public ActionResult ForceSessionRefresh()
{
HttpContext.GetOwinContext()
.Authentication.Challenge(new AuthenticationProperties { RedirectUri = "/Home/CheckSessiontimeout" },
OpenIdConnectAuthenticationDefaults.AuthenticationType);
return null;
}
我不确定这是否是最好的方法。这是我们所能做的最好的事情,以解决Azure AD和ASP.NET MVC应用程序(这些应用程序不是SPAs,不使用Web API,而是使用Ajax调用)的一系列困难限制,相对于我们的来源而言,这些都与执行Kerberos身份验证的本地应用程序无关(以及我们的用户对会话超时的期望,他们不想看到或担心)。
有两种方法可以处理这一问题(至少我们在应用程序中是这样做的;看看AD大师对此有什么看法会很有趣,这样我们也可以在这不是正确的做法时进行修复):
通用方法-使用刷新令牌
当你从AD获得访问令牌时,今天你会得到3样东西——访问令牌、访问令牌到期和刷新令牌。您所做的是将这三个文件全部缓存到应用程序中。在访问令牌到期之前,您可以简单地使用该访问令牌。一旦令牌过期,您就可以使用刷新令牌来获取新的访问令牌。ADAL中要用于此目的的方法是AcquireTokenByRefreshToken
。
话虽如此,您不应该在应用程序中对Refresh Token进行硬依赖。根据here
描述的最佳实践,刷新令牌可能会过期或失效。此外,基于Vittorio的post
,在ADAL版本3中甚至不返回刷新令牌。所以你可以考虑一下。
其他方法-静默获取代币
您可以采取的另一种方法是在令牌过期后代表用户以静默方式获取新令牌。我认为这要求用户必须在应用程序中手动登录至少一次,并遵循OAuth2流程。您要使用的方法是AcquireTokenSilent
。
以下是我们方法的伪代码:
var now = DateTime.UtcNow.Ticks;
if (now <= tokenExpiry && !string.IsNullOrWhiteSpace(accessToken))
return accessToken;
var clientCredential = new ClientCredential(ClientId, ClientSecret);
var authContext = new AuthenticationContext(string.Format("{0}/{1}",
AzureActiveDirectorySignInEndpoint,
azureADTenantId));
AuthenticationResult authResult = null;
if (!string.IsNullOrWhiteSpace(refreshToken))
{
authResult = await authContext.AcquireTokenByRefreshTokenAsync(refreshToken,
clientCredential,
ADEndpoint);
}
else
{
authResult = await authContext.AcquireTokenSilentAsync(Endpoint,
clientCredential,
new UserIdentifier(userId, UserIdentifierType.UniqueId));
}
return authResult.AccessToken;//Also you may want to cache the token again