更新: 以下の解決策は 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…
});
この状況のためだけに、ページに「refresherBox」の ID を持つ空の div がありますが、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);
}
TrackFrameReloads は、iframe の読み込みが完了するたびに発生します。差し迫った ADFS リダイレクトがあることがわかっているため、2 回発生します。1 回目はリダイレクト、2 回目はその src URL へのリダイレクトです。したがって、最初に起動したときは、loadcount をインクリメントするだけです。
2 回目の起動で、再認証に成功したことがわかります。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);
}
}
それらを定義した場合、エラーおよび完全な関数はすでに起動されていることに注意してください。
必要に応じて、ユーザーへの 2 つの警告メッセージをスキップできます。ADFS の設定にもよりますが、これには 1 秒しかかからず、ユーザーにこれが発生したことを通知する必要はまったくありません。