2

フロントエンドにangularjsを使用し、バックエンドの認証にレール+デバイスを使用しています。

フロント エンドでは/#/sign_in、xhr リクエストからの 401 応答でページにリダイレクトし、toastr を使用してグロウル スタイルのポップアップ メッセージを表示するための responseInterceptor を追加しました。

App.config(['$httpProvider', function ($httpProvider) {
  $httpProvider.responseInterceptors.push('securityInterceptor');
}]);

App.factory('securityInterceptor', ['$injector', '$location', '$cookieStore', function ($injector,$location,$cookieStore) {

  return function(promise) {
    var $http = $injector.get('$http');
      return promise.then(null, function(response){
        if (response.status === 401) {
          $cookieStore.remove('_angular_devise_user');
          toastr.warning('You are logged out');
          $location.path('/#/sign_in');
        }
      });
    };
});

私の問題は、コントローラーの初期化中にいくつかの xhr リクエストをロードするページをクリックしたときです。たとえば、次のようになります。

var products = Product.query();
var categories = Category.query();
var variations = Variation.query();

これらはさまざまなナビゲーション コンポーネントに必要であり、それらはすべて同時に起動するため、複数のうなり声スタイルのメッセージが重複して発生します。

angular を最初の 401 で終了させ、インターセプター内から残りのコントローラーの実行を停止する方法はありますか? 従来の Rails アプリでは、通常の実行を停止する「before_filter」があり、ページとクエリの読み込みが妨げられていました... angular でこれを行う最善の方法は何ですか?

4

1 に答える 1

0

私は自分のアプリでもこの問題について考えてきました。私の考えのスケッチ(実際の実装ではないので注意してください):

サービスは、ユーザーがログインしているuserDataかどうかとその他の情報 (ユーザー名、実際のユーザー名など) を追跡します。

App.service("userData", function() {
    var currentData = {
        loggedIn: false
    };

    function getCurrent() {
        return currentData;
    }

    // called when the user logs in with the user data
    function loggedIn(userData) {
        // the object is REPLACED to avoid race conditions, see explanation below
        currentData = angular.extend({loggedIn: true}, userData);
    }

    return {
        getCurrent: getCurrent,
        loggedIn: loggedIn
    };
});

インターセプターは、currentData. インターセプターが HTTP 401 を受信し、loggedInフラグがtrueの場合、フラグを にfalse変更し、ログイン ビューにリダイレクトします。インターセプターが HTTP 401 を受信し、loggedInフラグがfalseの場合、別のインターセプターがビューのリダイレクトを行っているため、要求を拒否する以外に何もしません。

ユーザーがログインすると、currentData応答が遅延する状況を回避するために、 が置き換えられます (たとえば、call1 と call2 が開始され、call1 が 401 に応答し、call2 も 401 になりますが、実際の応答の配信が遅延し、ユーザーがログに記録します)。その後、call2 はその 401 を受信します。2 番目の 401 は現在の状態を上書きしてはなりません)

App.config(["$provide", "$httpProvider", function($provide, $httpProvider) {
    $provide.factory("myHttpInterceptor", ["$q", "userData", "$cookieStore", "toastr", "$location",
        function($q, userData, $cookieStore, toastr, $location) {
            return {
                request: function(config) {
                    config.currentUserData = userData.getCurrent();
                    return config;
                },
                responseError: function(rejection) {
                    if( rejection && rejection.status === 401 && rejection.config && rejection.config.currentUserData && rejection.config.currentUserData.loggedIn ) {
                        rejection.config.currentUserData.loggedIn = false;
                        $cookieStore.remove('_angular_devise_user');
                        toastr.warning('You are logged out');
                        $location.path('/#/sign_in');
                    }
                    return $q.reject(rejection);
                }
            };
        }
    ]);

    $httpProvider.interceptors.push("myHttpInterceptor");
});

$httpProvider.responseInterceptorsまた、非推奨になっているように見えるため、インターセプターを登録するための新しい方法を使用していることにも注意してください。

于 2013-09-18T11:16:10.573 に答える