2015-01-05 8 views
5

Wir verwenden die DaftMonk/AngularJS Full-Stack-Generator für einen projet. Der generierte Code enthält die Logik zur Verwaltung der Benutzer (Registrierung, Anmeldung, Rollen usw.), was großartig ist. Bei der Verwendung des Codes tritt jedoch ein Problem auf, und die Rolle des aktuellen Benutzers ist manchmal undefiniert.GetCurrentUser(). Rolle in DaftMonk undefined/Generator-Winkel fullstack

Das Problem trat auf, als wir ein einfaches Feature implementieren wollten: Nach der Anmeldung/Anmeldung sollte der Benutzer auf eine URL umgeleitet werden, die von seiner Rolle abhängt. Zum Beispiel sollten 'teacher' Benutzer zu /teacherHome und 'student' Benutzer weitergeleitet werden sollten, um /studentHome umgeleitet werden. Da die Rolle "Auth.getCurrentUser()." Nicht definiert ist, funktioniert die Logik nicht.

Wie das Problem

reproduzieren das Problem zu reproduzieren, bearbeiten Sie die Datei und fügen Sie client/app/account/login/login.controller.js Aussagen den Wert von Auth.getCurrentUser einzuloggen() Rolle, etwa so:.

... 
    if(form.$valid) { 
    Auth.login({ 
     email: $scope.user.email, 
     password: $scope.user.password 
    }) 
    .then(function() { 
     // Logged in, redirect to home 
     console.log("Current user role: " + Auth.getCurrentUser().role); 
     $location.path('/'); 
    }) 
    .catch(function(err) { 
     $scope.errors.other = err.message; 
    }); 
    } 
}; 
... 

Wenn Sie diesen Code testen, werden Sie feststellen, dass die Benutzerrolle zu diesem Zeitpunkt nicht definiert ist. Später wird ihm jedoch ein Wert zugewiesen. Dies deutet darauf hin, dass das Problem möglicherweise auf einen asynchronen REST-Aufruf zurückzuführen ist.

Antwort

10

Es gibt tatsächlich ein paar damit zusammenhängende Probleme und Möglichkeiten, sie zu beheben.

Lösung 1: Verwenden Sie die mitgelieferte Auth.isLoggedInAsync Funktion

den AUTH-Modul, ein Teil des erzeugten Codes, ein Verfahren bereit, wenn der Anmeldevorgang abgeschlossen ist zu überprüfen (und eine Rückruffunktion aufzurufen, wenn dies der Fall). Also, eine Möglichkeit, das Problem zu beheben, ist diese Funktion im Client-Code zu verwenden, etwa so:

if(form.$valid) { 
    Auth.login({ 
     email: $scope.user.email, 
     password: $scope.user.password 
    }) 
    .then(function() { 
     // Logged in, redirect to home 
     console.log("Current user role: " + Auth.getCurrentUser().role); 
     Auth.isLoggedInAsync(function(success) { 
     console.log("Current user role: " + Auth.getCurrentUser().role); 
     }); 
     $location.path('/'); 
    }) 
    .catch(function(err) { 
     $scope.errors.other = err.message; 
    }); 
    } 
}; 

In diesem Fall werden Sie zwei Anweisungen in der Konsole angezeigt. Der erste wird zeigen, dass Auth.getCurrentUser(). Role noch nicht definiert ist. Der zweite wird zeigen, dass er jetzt einen Wert hat. Wenn Sie also eine Logik haben, die Sie zum Zeitpunkt der Anmeldung ausführen möchten und die von der Benutzerrolle (oder anderen Benutzerattributen) abhängt, legen Sie diese Logik in eine Rückruffunktion, die Sie an Auth.isLoggedInAsync() übergeben.

Lösung 2: behebt die Ursache in den auth.service.js

Wenn Sie den Code in client/components/auth/auth.service.js betrachten, werden Sie sehen, dass es ein Problem mit asynchronem Code ist. Das Problem ist, dass currentUser = User.get(); einen asynchronen HTTP-Aufruf auslöst und dass currentUser nicht sofort festgelegt wird (es ist ein nicht blockierender Aufruf). Da das Versprechen sofort gelöst wird, werden die Kunden davon überzeugt, dass der Anmeldevorgang abgeschlossen ist und alle Benutzerdaten verfügbar sind, während sie tatsächlich noch im Flug sind.

In der vorgeschlagenen Korrektur wird die Zusage in einer Callback-Funktion gelöst, die an User.get() übergeben wird.

/** 
    * Authenticate user and save token 
    * 
    * @param {Object} user  - login info 
    * @param {Function} callback - optional 
    * @return {Promise} 
    */ 
    login: function (user, callback) { 
    var cb = callback || angular.noop; 
    var deferred = $q.defer(); 

    $http.post('/auth/local', { 
     email: user.email, 
     password: user.password 
    }). 
    /* ORIGINAL CODE -- promise is resolved too early 
    success(function (data) { 
     $cookieStore.put('token', data.token); 
     currentUser = User.get(); 
     deferred.resolve(data); 
     return cb(); 
    }). 
    */ 
    /* PROPOSED FIX -- promise is resolved once HTTP call has returned */ 
    success(function (data) { 
     $cookieStore.put('token', data.token); 
     currentUser = User.get(function() { 
     deferred.resolve(data); 
     return cb(); 
     }); 
    }). 
    error(function (err) { 
     this.logout(); 
     deferred.reject(err); 
     return cb(err); 
    }.bind(this)); 

    return deferred.promise; 
    }, 

Verwandte Problem und beheben

Der vorgeschlagene Code behebt ein Problem. Es ist jetzt möglich, den Benutzer bei erfolgreicher Anmeldung auf eine bestimmte Seite umzuleiten. Ein ähnliches Problem tritt jedoch nach dem Anmeldevorgang auf.Auch in diesem Fall ist Auth.getCurrentUser().role für eine Weile undefiniert (lange genug für die Umleitungslogik fehlgeschlagen).

/** 
    * Create a new user 
    * 
    * @param {Object} user  - user info 
    * @param {Function} callback - optional 
    * @return {Promise} 
    */ 
    createUser: function (user, callback) { 
    var cb = callback || angular.noop; 

    /* ORIGINAL CODE --------------------- 
    return User.save(user, 
     function(data) { 
     $cookieStore.put('token', data.token); 
     currentUser = User.get(); 
     return cb(user); 
     }, 
     function(err) { 
     this.logout(); 
     return cb(err); 
     }.bind(this)).$promise; 
     --------------------- */ 

    /* PROPOSED FIX --------------------- */ 
    var deferred = $q.defer(); 
    User.save(user, 
     function (data) { 
     $cookieStore.put('token', data.token); 
     currentUser = User.get(function() { 
      console.log('User.save(), user role: ' + currentUser.role); 
      deferred.resolve(data); 
      return cb(currentUser); 
     }); 
     }, 
     function (err) { 
     this.logout(); 
     return cb(err); 
     deferred.reject(err); 
     }); 
    return deferred.promise; 

    }, 
+0

Sehr schöne und klare Lösung :) Vielen Dank:

In diesem Fall wurde der Code wie folgt festgesetzt –