更新:以下解决方案取决于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只是针对这种情况,与“refresherBox”的ID,但你可以做到这一点DOM中的任何元素。把一个iframe放到你的域中的某个虚拟页面上。就我而言,ADFSRefresher.cshtml的内容都只是
<div><input type="hidden" value="@DateTime.Now.ToString()" /></div>
而不是使用全局变量,我使用。数据()存储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秒钟,并且用户不必被通知任何这发生!
如果它是相关的,点击“是”继续将用户带到行动 - 这不是作为一个GET存在,所以他们然后得到一个404. – zimdanen 2013-03-27 20:28:10
你找到任何整洁的解决方案?在我们的例子中,我们正在考虑(如果我们可以检测到问题发生),在访问相关内部应用程序中新页面的页面上添加一个新的(隐藏的)iframe。将该新页面加载到'iframe'应该会触发ADFS服务器的完全被动流程,最终将在重新认证后加载新页面。此时,新页面将通过“postMessage”通知现有页面循环已完成,并且适当的cookie应该再次可用。 – 2013-08-29 12:30:14
@Damien_The_Unbeliever:由于时间问题和其他优先事项,我们没有继续深入探讨。 iframe解决方案对我来说很不好,但是,如果它是解决问题的唯一方法,那就是它。让我知道它是如何解决你的。 – zimdanen 2013-08-29 13:02:33