496 Stimmen

Umleitung zu einer bestimmten Route aufgrund einer Bedingung

Ich schreibe eine kleine AngularJS-Anwendung, die eine Login-Ansicht und eine Hauptansicht hat, wie so konfiguriert:

$routeProvider
 .when('/main' , {templateUrl: 'partials/main.html',  controller: MainController})
 .when('/login', {templateUrl: 'partials/login.html', controller: LoginController})
 .otherwise({redirectTo: '/login'});

Mein LoginController prüft die Kombination aus Benutzer und Passwort und setzt eine Eigenschaft auf $rootScope, die dies widerspiegelt:

function LoginController($scope, $location, $rootScope) {
 $scope.attemptLogin = function() {
   if ( $scope.username == $scope.password ) { // test
        $rootScope.loggedUser = $scope.username;
        $location.path( "/main" );
    } else {
        $scope.loginError = "Invalid user/pass.";
    }
}

Alles funktioniert, aber wenn ich auf http://localhost/#/main Am Ende umgehe ich den Anmeldebildschirm. Ich wollte etwas schreiben wie "wenn die Route sich ändert, wenn $rootScope.loggedUser null ist, dann zu /login umleiten".

...

... warte. Kann ich die Routenänderungen irgendwie abhören? Ich werde diese Frage trotzdem stellen und weiter suchen.

514voto

st.never Punkte 11733

Nachdem ich mich ein wenig durch die Dokumentation und den Quellcode gewühlt habe, glaube ich, dass ich es zum Laufen gebracht habe. Vielleicht ist das für jemand anderen nützlich?

Ich habe meiner Modulkonfiguration Folgendes hinzugefügt:

angular.module(...)
 .config( ['$routeProvider', function($routeProvider) {...}] )
 .run( function($rootScope, $location) {

    // register listener to watch route changes
    $rootScope.$on( "$routeChangeStart", function(event, next, current) {
      if ( $rootScope.loggedUser == null ) {
        // no logged user, we should be going to #login
        if ( next.templateUrl != "partials/login.html" ) {
          // not going to #login, we should redirect now
          $location.path( "/login" );
        }
      }         
    });
 })

Das Einzige, was mir seltsam vorkommt, ist, dass ich den Teilnamen ( login.html ), weil das "nächste" Route-Objekt keine Url oder etwas anderes enthielt. Vielleicht gibt es einen besseren Weg?

95voto

Nikolay Popov Punkte 1106

Hier ist vielleicht eine elegantere und flexiblere Lösung mit der Konfigurationseigenschaft "resolve" und "promises", die das eventuelle Laden von Daten beim Routing und Routing-Regeln in Abhängigkeit von den Daten ermöglichen.

Sie spezifizieren eine Funktion in 'resolve' in der Routing-Konfiguration und in der Funktion laden und prüfen Daten, tun alle Umleitungen. Wenn Sie Daten laden müssen, geben Sie ein Versprechen zurück, wenn Sie eine Umleitung durchführen müssen, weisen Sie das Versprechen vorher zurück. Alle Details finden Sie unter $routerProvider y $q Dokumentationsseiten.

'use strict';

var app = angular.module('app', [])
    .config(['$routeProvider', function($routeProvider) {
        $routeProvider
            .when('/', {
                templateUrl: "login.html",
                controller: LoginController
            })
            .when('/private', {
                templateUrl: "private.html",
                controller: PrivateController,
                resolve: {
                    factory: checkRouting
                }
            })
            .when('/private/anotherpage', {
                templateUrl:"another-private.html",
                controller: AnotherPriveController,
                resolve: {
                    factory: checkRouting
                }
            })
            .otherwise({ redirectTo: '/' });
    }]);

var checkRouting= function ($q, $rootScope, $location) {
    if ($rootScope.userProfile) {
        return true;
    } else {
        var deferred = $q.defer();
        $http.post("/loadUserProfile", { userToken: "blah" })
            .success(function (response) {
                $rootScope.userProfile = response.userProfile;
                deferred.resolve(true);
            })
            .error(function () {
                deferred.reject();
                $location.path("/");
             });
        return deferred.promise;
    }
};

Für russischsprachige Leute gibt es einen Beitrag auf habr " AngularJS ."

61voto

user1807337 Punkte 1070

Ich habe versucht, dasselbe zu tun. Nach der Zusammenarbeit mit einem Kollegen habe ich eine andere, einfachere Lösung gefunden. Ich habe eine Uhr eingerichtet auf $location.path() . Das ist der Trick. Ich fange gerade erst an, AngularJS zu lernen und finde dies sauberer und lesbarer.

$scope.$watch(function() { return $location.path(); }, function(newValue, oldValue){  
    if ($scope.loggedIn == false && newValue != '/login'){  
            $location.path('/login');  
    }  
});

36voto

Oran Dennison Punkte 3185

Eine andere Art der Implementierung der Login-Umleitung ist die Verwendung von Ereignissen und Abfängern als hier beschrieben . Der Artikel beschreibt einige zusätzliche Vorteile, wie z. B. die Erkennung, wenn eine Anmeldung erforderlich ist, die Einreihung der Anfragen in eine Warteschlange und die erneute Wiedergabe, sobald die Anmeldung erfolgreich ist.

Sie können eine funktionierende Demo ausprobieren aquí und sehen Sie sich die Demo-Quelle an aquí .

34voto

AJcodez Punkte 28477

1. Globalen aktuellen Benutzer einstellen.

Legen Sie in Ihrem Authentifizierungsdienst den aktuell authentifizierten Benutzer auf den Bereich Root fest.

// AuthService.js

  // auth successful
  $rootScope.user = user

2. Stellen Sie die Authentifizierungsfunktion für jede geschützte Route ein.

// AdminController.js

.config(function ($routeProvider) {
  $routeProvider.when('/admin', {
    controller: 'AdminController',
    auth: function (user) {
      return user && user.isAdmin
    }
  })
})

3. Prüfen Sie die Autorisierung bei jeder Routenänderung.

// index.js

.run(function ($rootScope, $location) {
  $rootScope.$on('$routeChangeStart', function (ev, next, curr) {
    if (next.$$route) {
      var user = $rootScope.user
      var auth = next.$$route.auth
      if (auth && !auth(user)) { $location.path('/') }
    }
  })
})

Alternativ können Sie Berechtigungen für das Benutzerobjekt festlegen und jeder Route eine Berechtigung zuweisen und dann die Berechtigung im Ereignis-Callback überprüfen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X