更新:以下解决方案取决于 iframe。 ADFS 3.0 的 X-Frame-Options 默认为 DENY,没有更改设置的选项。因此,此解决方案仅适用于 ADFS 2.1 及更早版本。
在您的 global.asax.cs 中,您将想要捕获任何中间 AJAX 302 并将它们变成 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;
}
}
然后,在那里拦截任何 401,然后再继续进行其余的错误处理。我选择向用户显示一条消息。您可以在此处执行下一步,但为了便于阅读,我将 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 放在一起,该 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);
}
}
请注意,如果您定义了它们,error 和 complete 函数将已经被触发。
如果您愿意,您可以跳过向用户发送的两条警报消息。根据您的 ADFS 设置,这应该只需要 1 秒钟,并且根本不需要通知用户这一切发生了!