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

上一篇: ADFS session expires and causes error

下一篇: line code with Jekyll and Pygments?