4

私のプロジェクトではWIFを使用しています(ただし、これはこの質問のコンテキストではそれほど重要ではありません。認証を処理する代替フレームワークを使用できます。質問は、ajaxリクエストの実行中の認証失敗の処理に関するものです)。それにもかかわらず、私の場合、から継承しClaimsAuthenticationManager、認証を処理するカスタム サーバー ロジックを作成しました。

public override IClaimsPrincipal Authenticate(string resourceName, IClaimsPrincipal incomingPrincipal)
{
    if (incomingPrincipal != null && incomingPrincipal.Identity.IsAuthenticated)
    {
        // add some custom claims
    }
    return incomingPrincipal;
}

ここで、すべてのSession Cookiesを削除し、終了して任意のページに再び入ると、WIF が提供するログイン ページにリダイレクトされ、再度ログインするように要求されます。すべてが期待どおりに機能します。

しかし、代わりにajax リクエストを行うと、エラーが発生します。これは次のようにインターセプトされます。

$(document).ready(function () {
    $.ajaxSetup({
        error: function (XMLHttpRequest, textStatus, errorThrown) {            
            // do something
        }
    });
});

残念ながら、XMLHttpRequestオブジェクトは意味のあるメッセージを返しません。これに基づいて、この種のエラーを他の方法で処理できます。この特定のケースでは、通常のリクエストと同様に、アプリケーションをログイン ページにリダイレクトさせたいだけです。

ここに画像の説明を入力

ajax 呼び出しの実行中に、メソッドAuthenticatefromClaimsAuthenticationManagerが呼び出されます。Identity.IsAuthenticatedfalse を返し、メソッドが終了し、すべてが完了します。OnAuthorizationメソッド fromもBaseController呼び出されないため、ajax の結果オブジェクトにステータスを渡すことができません。

protected override void OnAuthorization(AuthorizationContext filterContext)
{
    if (filterContext.HttpContext.Request.IsAjaxRequest() && !User.Identity.IsAuthenticated)
    {
        //do something, for example pass custom result to filterContext
    }
    base.OnAuthorization(filterContext);
}

パズルを解くには?

4

1 に答える 1

7

これに関するいくつかのリソースを見つけました(回答の下部を参照)、次の解決策と混同しました:

ajax リクエストの実行中に、json を戻すように指定しました。

$.ajax({
    url: action,
    type: 'POST',
    dataType: 'json',
    data: jsonString,
    contentType: 'application/json; charset=utf-8',
    success:
        function (result, textStatus, xhr) {
        }
});

私のフレームワークは認証を処理するため、トークンの有効期限が切れる間、応答に http ステータス 302 を入れます。ブラウザーで透過的に 302 応答を処理したくないので、Global.asax でそれをキャッチし、ステータスを 200 OK に変更しました。さらに、特別な方法でそのような応答を処理するように指示するヘッダーを追加しました。

protected void Application_EndRequest()
{
    if (Context.Response.StatusCode == 302
        && (new HttpContextWrapper(Context)).Request.IsAjaxRequest())
    {                
        Context.Response.StatusCode = 200;
        Context.Response.AddHeader("REQUIRES_AUTH", "1");
    }
}

応答コンテンツが json に正しくシリアル化されていないため、解析エラーが発生します。エラー イベントが呼び出され、その中でリダイレクトが実行されます。

$(document).ready(function () {
    $.ajaxSetup({
        error: function (XMLHttpRequest, textStatus, errorThrown) {
            if (XMLHttpRequest.getResponseHeader('REQUIRES_AUTH') === '1') {
                // redirect to logon page
                window.location = XMLHttpRequest.getResponseHeader('location');
            }
            // do sth else
        }
    });
});

詳細については、jQuery Ajax 呼び出し後にリダイレクト要求を管理する方法とユーザー セッションの有効期限が切れたとき、または要求が 302で終了したときに AJAX 要求を処理する方法を参照してください。

アップデート:

その間、私は新しい解決策を見つけました。私の意見では、はるかに優れています。なぜなら、そのままですべての ajax リクエストに適用できるからです (明らかに beforeSend イベントを再定義しない場合):

$.ajaxSetup({
    beforeSend: checkPulse,
    error: function (XMLHttpRequest, textStatus, errorThrown) {
        document.open();
        document.write(XMLHttpRequest.responseText);
        document.close();
    }
});

function checkPulse(XMLHttpRequest) {
    var location = window.location.href;
    $.ajax({
        url: "/Controller/CheckPulse",
        type: 'GET',
        async: false,
        beforeSend: null,
        success:
            function (result, textStatus, xhr) {
                if (xhr.getResponseHeader('REQUIRES_AUTH') === '1') {
                    XMLHttpRequest.abort(); // terminate further ajax execution
                    window.location = location;
                }
            }
    });
}

コントローラーメソッドは、最も単純なものであれば何でもかまいません:

[Authorize]
public virtual void CheckPulse() {}

Application_EndRequest()と同じままです。

于 2012-06-18T08:02:21.700 に答える