ADFS会话过期并导致错误
我们将ADFS用于我们的内部应用程序 - 用户基本上都可以透明地登录到他们的应用程序中。 但是,如果用户将页面打开一个多小时,然后尝试在该页面上执行某些操作(除了导航到另一页面),则会显示错误消息:
此页面正在访问不受其控制的信息。 这带来了安全风险。 你想继续吗?
看起来页面正在尝试将该请求重定向到ADFS服务器,并且浏览器正在阻止该请求。
因此我的问题是:如何捕获这种情况并让用户访问ADFS服务器以重新进行身份验证?
我没有在Google上找到任何有关此事的运气。
您可以在global.asax中手动检查并重新发出安全令牌,并使用它创建滑动会话。 通过滑动会话,您可以选择推迟重新验证,直到它变为“安全”(这样做时(由于ADFS重定向而不再丢失数据)。
在SessionSecurityTokenReceived事件中,您可以评估令牌和请求。 如果令牌已过期并且请求会经历重定向导致的数据丢失,则可以重新发布新的“临时”令牌。 新的令牌应该有一个非常短的寿命,只要足够长的时间,以便您可以安全地完成当前的请求。 令牌将过期并在下一次请求时再次评估。
protected void SessionAuthenticationModule_SessionSecurityTokenReceived(object sender, SessionSecurityTokenReceivedEventArgs e)
{
var now = DateTime.UtcNow;
SessionSecurityToken token = e.SessionToken;
var httpContext = new HttpContextWrapper(this.Context);
if (now > token.ValidTo
&& (httpContext.Request.IsAjaxRequest() || httpContext.Request.HttpMethod == "POST"))
{
var sessionAuthModule = (SessionAuthenticationModule)sender;
e.SessionToken = sessionAuthModule.CreateSessionSecurityToken(token.ClaimsPrincipal,
token.Context,
now,
now.AddMinutes(2),
token.IsPersistent);
e.ReissueCookie = true;
}
}
ADFS会话将继续推迟重新认证,直到下一个GET请求。 然后重定向最终会发生,并且用户将被发出正常寿命的正确标记。
更新:以下解决方案取决于iframe。 ADFS 3.0的X-Frame-Options默认为DENY,无法更改设置。 因此,此解决方案仅适用于ADFS 2.1及更早版本。
在你的global.asax.cs中,你会想要抓住任何mid-AJAX 302s并将它们变成401 Unauthorized。 这将阻止进行调用(并弹出该消息),并将发送给我们$(document).ajaxError()。
protected void Application_EndRequest()
{
var context = new HttpContextWrapper(this.Context);
if (context.Response.StatusCode == 302 && context.Request.IsAjaxRequest())
{
context.Response.Clear();
context.Response.StatusCode = 401;
}
}
然后,在那里,拦截任何401s,然后继续进行其他错误处理。 我选择向用户显示一条消息。 您可以在这里执行下一步,但为了便于阅读,我将ajaxSettings对象发送给另一个函数。 返回true,以便它不会继续进行其他错误处理。
如果您想重新检查这是ADFS,则event.target.referrer将具有尝试重定向的URL。
$(document).ajaxError(function (event, jqXHR, ajaxSettings, thrownError) {
if (xhr.status == 401) {
alert("Your session has timed out. Click OK to reauthorize and extend your session.");
TriggerReauthenticationRefresher(ajaxSettings);
return true;
}
…the rest of the error handling code…
});
在我的页面中有一个空的div,仅用于这种情况,ID为'refresherBox',但是您可以在DOM中的任何元素上执行此操作。 把一个iframe放到你的域中的某个虚拟页面上。 在我的情况下,ADFSRefresher.cshtml的内容只是
<div><input type="hidden" value="@DateTime.Now.ToString()" /></div>
我使用.data()存储ajaxSettings,而不是使用全局变量。 我们还需要跟踪iframe重新加载的次数,因此我们还要存储loadcount。 将iframe插入到DOM中,它会启动。
function TriggerReauthenticationRefresher(ajaxSettings) {
var refreshframe = '<iframe src="@Url.Action("ADFSRefresher", "Debug")" style="display:none" onload="TrackFrameReloads()" />';
$('#refresherBox').data('loadcount', 0);
$('#refresherBox').data('originalRequestSettings', ajaxSettings);
$('#refresherBox').html(refreshframe);
}
每次iframe完成加载时,TrackFrameReloads都会触发。 由于我们知道即将发生的ADFS重定向,它将会启动两次。 第一次是重定向,第二次是到它的src url。 所以第一次启动时,我们只是增加loadcount。
第二次触发时,我们知道我们已经成功重新认证。 检索ajaxSettings,清除存储的数据,然后可以重新使用原始设置发送AJAX调用! 它将通过,不重定向,并运行其原有的成功和完整的功能。
function TrackFrameReloads() {
var i = $('#refresherBox').data('loadcount');
if (i == 1) {
alert('Your session has been extended.');
var ajaxSettings = $('#refresherBox').data('originalRequestSettings');
$('#refresherBox').removeData();
$.ajax(ajaxSettings);
} else {
$('#refresherBox').data("loadcount", 1);
}
}
请注意,如果你定义了它们,那么错误和完整的函数将会被触发。
如果您愿意,您可以跳过两条警报消息给用户。 根据您的ADFS设置,这应该只需要1秒钟,并且用户不必被通知任何这发生!
链接地址: http://www.djcxy.com/p/70259.html