javascript AD FS 2.0身份验证和 AJAX

ttp71kqs  于 2023-02-21  发布在  Java
关注(0)|答案(7)|浏览(332)

我有一个网站正在尝试调用另一个网站上的MVC控制器操作。这两个网站都设置为AD FS 2.0中的依赖方信任。在两个网站之间的浏览器窗口中打开页面时,一切都经过身份验证并正常工作。但是,当尝试使用 AJAX 方法从JavaScript调用一个控制器动作时,总是失败。下面是我尝试做的事情的代码片段。。

$.ajax({
  url: "relyingPartySite/Controller/Action",
  data: { foobar },
  dataType: "json",
  type: "POST",
  async: false,
  cache: false,
  success: function (data) {
    // do something here
  },
  error: function (data, status) {
    alert(status);
  }
});

问题是AD FS使用JavaScript向依赖方发布隐藏的html表单。使用Fiddler跟踪时,我可以看到它到达AD FS站点并返回此html表单,该表单应发布并重定向到经过身份验证的控制器操作。问题是这个表单作为 AJAX 请求的结果返回,并且显然会失败,因为ajax请求期望来自控制器的json这似乎是一个常见的场景,那么从 AJAX 与AD FS通信并处理此重定向的正确方法是什么呢?

jqjz2hbq

jqjz2hbq1#

您有两个选择。更多信息here
第一种是在入口应用程序(基于HTML的应用程序)和API解决方案之间共享会话cookie。您可以配置这两个应用程序使用相同的WIF cookie。这仅在两个应用程序位于同一根域时有效。请参阅上面的帖子或此stackoverflow question
另一个选项是禁用 AJAX 请求的passiveRedirect(如Gutek's answer)。这将返回一个http状态代码401,您可以在Javascript中处理。当您检测到401时,你加载了一个虚拟页面(或“验证”对话框,如果需要再次提供凭据,则该对话框可兼作登录对话框)。当iFrame完成后,您可以再次尝试调用。这一次,会话cookie将出现在调用中,并且调用应该成功。

//Requires Jquery 1.9+
var webAPIHtmlPage = "http://webapi.somedomain/preauth.html"

function authenticate() {
    return $.Deferred(function (d) {
        //Potentially could make this into a little popup layer 
        //that shows we are authenticating, and allows for re-authentication if needed
        var iFrame = $("<iframe></iframe>");
        iFrame.hide();
        iFrame.appendTo("body");
        iFrame.attr('src', webAPIHtmlPage);
        iFrame.load(function () {
            iFrame.remove();
            d.resolve();
        });
    });
};

function makeCall() {
    return $.getJSON(uri)
                .then(function(data) {
                        return $.Deferred(function(d) { d.resolve(data); });
                    },
                    function(error) {
                        if (error.status == 401) {
                            //Authenticating, 
                            //TODO:should add a check to prevnet infinite loop
                            return authenticate().then(function() {
                                //Making the call again
                                return makeCall();

                            });
                        } else {
                            return $.Deferred(function(d) {
                                d.reject(error);
                            });
                        }
                });
}
kiayqfof

kiayqfof2#

如果您不想接收带有链接的HTML,可以在WSFederationAuthenticationModule上处理AuthorizationFailed,并仅在Ajax调用时将RedirectToIdentityProvider设置为false
例如:

FederatedAuthentication.WSFederationAuthenticationModule.AuthorizationFailed += (sender, e) =>
{
    if (Context.Request.RequestContext.HttpContext.Request.IsAjaxRequest())
    {
        e.RedirectToIdentityProvider = false;
    }
};

Authorize属性将返回状态代码401,如果您希望有不同的内容,则可以实现自己的Authorize属性并在Ajax请求上编写特殊代码。

snz8szmq

snz8szmq3#

在我目前工作的项目中,我们遇到了同样的问题,客户端上的SAML令牌过期,导致 AJAX 调用出现问题。在我们的特定情况下,我们需要在遇到第一个401后将所有请求排队,并在成功认证后重新发送所有请求。认证使用Adam米尔斯建议的iframe解决方案,而且在需要输入用户凭证的情况下更进一步,这是通过显示通知用户登录外部视图的对话框来完成的(由于ADFS不允许在iframe中显示登录页面,至少不允许在默认配置中显示)在此期间,等待请求正在等待完成,但用户需要从外部页面登录。如果用户选择取消,也可以拒绝等待请求,在这种情况下,将为每个请求调用jquery错误。
下面是示例代码要点的链接:
https://gist.github.com/kavhad/bb0d8e4a446496a6c05a
注意我的代码是基于jquery处理所有 AJAX 请求的用法。如果你的ajax请求是由vanilla javascript,其他库或框架处理的,那么你可能会在这个例子中找到一些灵感。jquery用户界面的用法仅仅是因为对话框,代表了一小部分代码,可以很容易地被替换掉。

更新抱歉我更改了我的github帐户名,这就是为什么链接不起作用。现在应该可以了。

chhkpiq4

chhkpiq44#

首先你说你正在尝试对另一个网站进行 AJAX 调用,你的调用是否符合网页浏览器的same origin policy?如果符合,那么你希望从服务器得到html作为响应,将ajax调用的datatype更改为dataType: "html",然后将表单插入到DOM中。

4nkexdtk

4nkexdtk5#

也许this serie的前两篇文章会对你有所帮助。他们考虑了ADFS和 AJAX 请求
我想我会尝试做的是看看为什么认证cookie不通过 AJAX 传输,并找到一种方法来发送它们与我的请求.或者 Package ajax调用在一个函数中,通过检索html表单,将其隐藏地附加到DOM,提交它(它将有希望设置好cookie),然后发送您最初想要发送的适当请求来进行预认证

km0tfn4u

km0tfn4u6#

只能使用此类型的数据类型

"xml": Treat the response as an XML document that can be processed via jQuery. 

"html": Treat the response as HTML (plain text); included script tags are evaluated. 

"script": Evaluates the response as JavaScript and evaluates it. 

"json": Evaluates the response as JSON and sends a JavaScript Object to the success callback.

如果你能看到你的fiddler只返回html,那么就把你的数据类型改为html,或者如果那只是一个脚本代码,那么你就可以使用script。

6ss1mwsb

6ss1mwsb7#

你应该创建一个像json.php这样的任意名称的文件,然后把连接到relayparty网站,这应该工作$.ajax({ url: "json.php", data: { foobar }, dataType: "json", type: "POST", async: false, cache: false, success: function (data) { // do something here }, error: function (data, status) { alert(status); } });

相关问题