簡體   English   中英

AD FS 2.0身份驗證和AJAX

[英]AD FS 2.0 Authentication and AJAX

我有一個網站試圖在另一個網站上調用MVC控制器操作。 這些站點都設置為AD FS 2.0中的信賴方信任。 在兩個站點之間的瀏覽器窗口中打開頁面時,一切都經過身份驗證和正常工作。 但是,當嘗試使用jQuery 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進行通信並處理此重定向的正確方法是什么?

你有兩個選擇。 更多信息在這里

第一種是在條目應用程序(基於HTML的應用程序)和API解決方案之間共享會話cookie。 您將兩個應用程序配置為使用相同的WIF cookie。 這僅適用於兩個應用程序位於同一根域的情況。 請參閱上面的帖子或此stackoverflow問題

另一種選擇是禁用AJR請求的passiveRedirect(作為Gutek的答案 )。 這將返回一個可以在Javascript中處理的http狀態代碼401。 當您檢測到401時,您會在iFrame中加載虛擬頁面(或“Authenticating”對話框,如果需要再次提供憑據,則該對話框可以兼作登錄對話框)。 當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);
                            });
                        }
                });
}

如果您不希望接收帶有鏈接的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請求上編寫特殊代碼。

在我目前使用的項目中,我們遇到了與客戶端上的SAML令牌過期相同的問題,並導致ajax調用問題。 在我們的特定情況下,我們需要在遇到第一個401之后將所有請求排入隊列,並且在成功驗證之后,可以重新發送所有請求。 身份驗證使用Adam Mills建議的iframe解決方案,但在需要輸入用戶憑據的情況下也會更進一步,這通過顯示一個對話框來通知用戶登錄外部視圖(因為ADFS不允許顯示登錄) iframe中的頁面至少是默認配置)等待請求等待完成但用戶需要從外部頁面登錄。 如果用戶選擇取消,也可以拒絕等待請求,在這些情況下,將為每個請求調用jquery錯誤。

這是一個帶有示例代碼的要點的鏈接:

https://gist.github.com/kaveh82/bb0d8e4a446496a6c05a

請注意,我的代碼基於jquery的用法來處理所有ajax請求。 如果您的ajax請求由vanilla javascript,其他庫或框架處理,那么您可以在此示例中找到一些靈感。 jquery ui的用法僅僅是因為對話框而且代表了一小部分代碼,可以很容易地換出。

首先,你說你正在嘗試對另一個網站進行ajax調用,你的調用是否符合Web瀏覽器的相同原始策略 如果確實如此,那么您希望將html作為服務器的響應,將ajax調用的datatype更改為dataType: "html" ,然后將表單插入到DOM中。

也許這個系列的2個帖子會幫助你。 他們考慮ADFS和AJAX請求

我認為我會嘗試做的是看看為什么身份驗證cookie不是通過ajax傳輸的,並找到一個意思是用我的請求發送它們。 或者將ajax調用包裝在一個函數中,該函數通過檢索html表單進行預驗證,將其隱藏到DOM中,提交它(它有望設置好的cookie)然后發送你想要發送的相應請求

您只能執行此類數據類型

"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,或者如果只有腳本代碼,那么您可以使用腳本。

您應該創建一個文件任何名稱,如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); } });

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM