2013-06-23 9 views
6

Poszukuję solidnego sposobu na udostępnienie "bieżącego identyfikatora użytkownika" we wszystkich kontrolerach. Korzystanie z: Firebase Proste logowanie: Email/Password AuthenticationFACTORY: pobierz bieżące user.id dla Firebase Proste logowanie (e-mail/hasło)

Moja ida: Potrzebuję "fabryki", którą mogę wprowadzić do kontrolerów, , aby "aktualny identyfikator użytkownika" był zawsze dostępny.

wymyśliłem ten kod:

app.factory('User', ['angularFire', 

    //Get Current UserID 

    function(angularFire){ 

     console.log ('FACTORY: User'); 
      var currentUser = {}; 
      var ReturnStr = ''; 
     var ref = new Firebase("https://myFIREBASE.firebaseio.com/"); 
     var authClient = new FirebaseAuthClient(ref, function (err, user) { 

      if (err) { 
        ReturnStr = 'FACTORY: User Error: ' + err; 
       console.log (ReturnStr); 
         //var User = ReturnStr; 
      } else if (user) { 
       console.log ('FACTORY: User: Login successfully:'); 
       console.log (user); 
       currentUser = user; 
      } else { 
       //console.log ('-----------User: Logged Out ---------------'); 
        ReturnStr = 'FACTORY: Logged out: Redirect to Login'; 
       console.log (ReturnStr); 
       window.location.href = "/login.php"; 
      } 
     }); 

    return currentUser; 
     } 
]); 

Moja najprostsza Kontroler wygląda następująco:

function ToDoCtrl($scope, User) { 
    $scope.MyUser = User; 
    $scope.MyUser.test = 'Test'; 
} 

W HTML (kątowych podszablonów) mam:

<h2>{{MyUser.id}}</h2> 
<h2>{{MyUser.email}}</h2> 
<h2>{{MyUser.provider}}</h2> 
<h2>{{MyUser.test}}</h2> 

=> id , e-mail, dostawca są "niezdefiniowani". W konsoli widzę "FACTORY: User: Login successfully:" z poprawnym użytkownikiem - Object.

=> Asynchroniczny problem z ładowaniem danych?

Mam również eksperymentował (bez powodzenia):

 $timeout(function() { 
     currentUser = user; 
     } 

Taka fabryka byłaby bardzo przydatna! Dzięki za wskazanie mnie we właściwym kierunku!

Edycja 1.1: Teraz z $ rootscope włamać

=> sam efekt - MyController jest zbyt szybki - fabryka zwalniać.

app.factory('User', ['$rootScope', '$timeout', 'angularFire', 

    //Aktueller Benutzer auslesen 

    function($rootScope, $timeout, angularFire){ 

     console.log ('FACTORY: User'); 
      var currentUser = {}; 
      var ReturnStr = ''; 
     var ref = new Firebase("https://openpsychotherapy.firebaseio.com/"); 
     var authClient = new FirebaseAuthClient(ref, function (err, user) { 

      if (err) { 
        ReturnStr = 'FACTORY: User Error: ' + err; 
       console.log (ReturnStr); 
         //var User = ReturnStr; 
      } else if (user) { 
       console.log ('FACTORY: User: Login successfully:'); 
         //currentUser = user; 

      $timeout(function() { 
         ReturnStr = 'FACTORY: Inside timout'; 
        console.log (ReturnStr); 

          currentUser = user; 
        console.log (currentUser); 

       $rootScope.myUser = user; 
       $rootScope.myUserID = user.id; 
       $rootScope.loggedIn = true; 
          $rootScope.$apply(); 

        return currentUser; 
      }); 


      } else { 
       //console.log ('-----------User: Logged Out ---------------'); 
        ReturnStr = 'FACTORY: Logged out: Redirect to Login'; 
       console.log (ReturnStr); 
         //var User = ReturnStr; 
       window.location.href = "/login.php"; 
      } 
     }); 

    return currentUser; 
     } 
]); 

TAHNKS za wszelkie pomocne sugestie! Zastanów się, jak inni to rozwiązują!

+0

Zrobiłem solidny system logowania z tymi ognistymi rzeczami, które opublikuję, kiedy wrócę do domu. To może być idealne do tego, co próbujesz tutaj zrobić. – jaredwilli

Odpowiedz

14

Oto moje rozwiązanie tego problemu. Używam Firebase, FirebaseAuthClient i angularFire dla mojej aplikacji Angular. Wpadłem na tę samą sytuację w moim systemie logowania, w którym nie można wstrzyknąć $ scope do fabryki i dlatego wymyśliłem kontroler, który używał fabryki do jej pobierania, dodawania, aktualizowania i usuwania. I w kontrolerze mam uruchamiane rzeczy z firebaseAuth, ustawienie wartości User i odnośniki, które przypisuję do tego zakresu. Po zalogowaniu użytkownik zostaje przekierowany do innej lokalizacji, w którym to momencie plik app.js przejmuje kontroler podrzędny, gdy znajduje się w tej lokalizacji adresu.

Mój login również używa localStorage, więc loginy będą się utrzymywać, możesz odświeżyć i nie będziesz musiał logować się, a możesz to zmienić tak, aby pliki cookie lub sessionStorage były wystarczająco łatwe.

To będzie trzeba dostosować do twoich potrzeb, jeśli zdecydujesz się użyć tej metody, jest to dość skomplikowane, bez względu na wszystko, ale jest to dla mnie bardzo solidne i nie muszę już martwić się o firebaseAuth lub Teraz, gdy moje fabryki są skonfigurowane do przekazywania danych tam iz powrotem. Po prostu robię rzeczy angularowe głównie z dyrektywami. Oto mój kod.

UWAGA: To będzie wymagać modyfikacji, a niektóre rzeczy będą pseudo lub otwarte, abyś mógł określić swoje potrzeby.

AuthCtrl.js

'use strict'; 

angular.module('YOUR_APP', []). 
controller('AuthCtrl', [ 
'$scope', 
'$location', 
'angularFire', 
'fireFactory', 

function AuthCtrl($scope, $location, angularFire, fireFactory) { 
    // FirebaseAuth callback 
    $scope.authCallback = function(error, user) { 
     if (error) { 
      console.log('error: ', error.code); 
      /*if (error.code === 'EXPIRED_TOKEN') { 
       $location.path('/'); 
      }*/ 
     } else if (user) { 
      console.log('Logged In', $scope); 
      // Store the auth token 
      localStorage.setItem('token', user.firebaseAuthToken); 
      $scope.isLoggedIn = true; 

      $scope.userId = user.id; 

      // Set the userRef and add user child refs once 
      $scope.userRef = fireFactory.firebaseRef('users').child(user.id); 
      $scope.userRef.once('value', function(data) { 
       // Set the userRef children if this is first login 
       var val = data.val(); 
       var info = { 
        userId: user.id, 
        name: user.name 
       }; 
       // Use snapshot value if not first login 
       if (val) { 
        info = val; 
       } 
       $scope.userRef.set(info); // set user child data once 
      }); 

      $location.path('/user/' + $scope.userRef.name()); 
     } else { 
      localStorage.clear(); 
      $scope.isLoggedIn = false; 
      $location.path('/'); 
     } 
    }; 

    var authClient = new FirebaseAuthClient(fireFactory.firebaseRef('users'), $scope.authCallback); 

    $scope.login = function(provider) { 
     $scope.token = localStorage.getItem('token'); 
     var options = { 
      'rememberMe': true 
     }; 
     provider = 'twitter'; 

     if ($scope.token) { 
      console.log('login with token', $scope.token); 
      fireFactory.firebaseRef('users').auth($scope.token, $scope.authCallback); 
     } else { 
      console.log('login with authClient'); 
      authClient.login(provider, options); 
     } 
    }; 

    $scope.logout = function() { 
     localStorage.clear(); 
     authClient.logout(); 
     $location.path('/'); 
    }; 
} 

]);

A teraz dla ładnej i prostej, ale całkiem wielorazowej fabryki. Aby mogła działać, musisz ustawić ścieżkę Firebase dla swojej aplikacji na zmienną baseUrl.

fireFactory.js

'use strict'; 
angular.module('YOUR_APP'). 
factory('fireFactory', [ 
function fireFactory() { 
    return { 
     firebaseRef: function(path) { 
      var baseUrl = 'https://YOUR_FIREBASE_PATH.firebaseio.com'; 
      path = (path !== '') ? baseUrl + '/' + path : baseUrl; 
      return new Firebase(path); 
     } 
    }; 
} 

]);

Info

Dajesz fabryce tylko kawałek toru odniesienia, takie jak „użytkowników”, które będą wykorzystywane w ramach pełnej ścieżki wg gdzie chcesz przechowywać swoje dane użytkownika.

fireFactory.firebaseRef('users') 

Gdy masz referencyjnej określonej dla użytkownika, nie będzie trzeba ustawiać ponownie będzie to po prostu korzystać z istniejących danych i .auth() do niego. Dodatkowo, jeśli istnieje lokalny "token" w localStorage, użyje go do autoryzacji użytkownika.

W przeciwnym razie zaloguje się() i otworzy okna Oautha, aby to zrobić, korzystając z dowolnej opcji, którą im podasz.

Spędziłem dużo czasu, wiele godzin, a nawet miesięcy szukając czegoś lepszego niż to, jeśli chodzi o Firebase/FirebaseAuthClient i angularFire. Ze względu na sposób, w jaki interfejs API Firebase i FireAuth API jest bardzo uciążliwy, można je dobrze odtwarzać podczas korzystania z nich za pomocą metody angularFire. To bardzo frustrujące, ale w końcu udało mi się to osiągnąć.

Jeśli chcesz sprawdzić kod mojej aplikacji i zobaczyć, jak robię te rzeczy bardziej kompletnie, możesz ją znaleźć w this branch of my Webernote github repo.

Możesz go rozwidlić, zainstalować i uruchomić lokalnie lub wnieść do niego swój wkład, nawet jeśli chcesz. Przydałaby mi się pomoc :)

Mam nadzieję, że to pomoże!

+0

To naprawdę pomogło mi rozwiązać podobny problem, dziękuję za udostępnienie. –

+0

Chętnie pomogę. Cieszę się, że uznałeś to za przydatne. :) – jaredwilli

+0

dzięki za udostępnienie kodu – Iladarsda

0

Jest to najprawdopodobniej spowodowane asynchroniczną naturą połączenia. Aby to naprawić trzeba by

  • wstrzyknąć $scope do funkcji fabrycznego (podobny do angularFire uzależnienia)
  • Korzystanie $scope.$apply() po assigment currentUser = user;
+0

Dzięki! Tak, jest to problem asynchroniczny. Teraz mam to: Błąd: Nieznany dostawca: $ scopeProvider <- $ scope <- Użytkownik Moja obecna Factory wygląda tak: Sprawdź Edit1 –

+0

Teraz muszę zapytać: howto wstrzyknąć $ scope do funkcji fabrycznej? Dzięki za pomoc! –

+1

=> Fabryki nie mają dostępu do bieżącego kontrolera/zakresu dyrektywy, ponieważ ich nie ma. Mają jednak dostęp do katalogu głównego aplikacji i dlatego jest dostępny $ rootScope. (http://stackoverflow.com/questions/14056874/how-to-emit-events-from-a-factory) => Eksperyment z $ rootscope –

1

oto sposób to zrobić.

Przede wszystkim mam autoryzację firebase (nie używam Angularfire), która dzwoni do Singly, aby obsługiwać logowanie. Gdy status użytkownika zmienia się, $ nadaje wydarzenie.

p4pApp.factory('firebaseAuth', function($rootScope, singlyAuth) { 
var auth = {}, 
    FBref = new Firebase(p4pApp.FIREBASEPATH); 

auth.login = function(service) { 
    singlyAuth.login(service); 
}; 

auth.logout = function() { 
    FBref.unauth(); 
    auth.user = null; 
    auth.broadcastAuthEvent(); 
}; 

auth.broadcastAuthEvent = function() { 
    $rootScope.$broadcast('authEvent'); 
}; 

auth.authWithToken = function(token) { 
    if (token !== undefined) { 
     FBref.auth(token, function(error, authData) { 
      if(!error) { 
       auth.user = authData.auth.account; 
       auth.broadcastAuthEvent(); 
      } else { 
       auth.user = null; 
       auth.broadcastAuthEvent(); 
      } 
     }, function(error) { 
      auth.user = null; 
      auth.broadcastAuthEvent(); 
     }); 
    } 
}; 

return auth; 
}); 

Następnie mam kontroler "najwyższego poziomu", który sprawdza stan autoryzacji.

var AuthCtrl = function($scope, firebaseAuth, singlyAuth, firebase, user) { 
$scope.user = null; 

$scope.logout = function() { 
    firebaseAuth.logout(); 
}; 

$scope.isLoggedIn = function() { 
    return !!$scope.user; 
}; 

// src: Alex Vanston (https://coderwall.com/p/ngisma) 
$scope.safeApply = function(fn) { 
    var phase = this.$root.$$phase; 
    if (phase == '$apply' || phase == '$digest') { 
     if(fn && (typeof(fn) === 'function')) { 
      fn(); 
     } 
    } else { 
     this.$apply(fn); 
    } 
}; 

$scope.$on('authEvent', function() { 
    $scope.safeApply(function() { 
     $scope.user = firebaseAuth.user; 
    }); 

    user.setID(firebaseAuth.user); 

    if (firebaseAuth.user) { 
     firebase.fetch(['users', firebaseAuth.user], function(results) { 
      if (results) { 
       user.setData(results); 
      } else { 
       results = {}; 
       results.createdAt = DateTimeStamp(); 
      } 

      results.lastLogin = DateTimeStamp(); 

      firebase.set('users', firebaseAuth.user, results); 
     });  
    } else { 
     user.clearData(); 
    } 
}); 
}; 

Wreszcie, korzystam z dedykowanej usługi użytkownika, aby utrzymać stan użytkownika.(Jest jeszcze w fazie rozwoju)

p4pApp.factory('user', function() { 
var userService = {}, user={}; 

user.data = {}; 

userService.setID = function(id) { 
    user.id = id; 
}; 

userService.getID = function() { 
    return user.id; 
}; 

userService.setData = function(data) { 
    user.data = data || {}; 
}; 

userService.getData = function() { 
    return user.data; 
}; 

userService.clearData = function() { 
    user.data = {}; 
}; 

userService.setDataField = function(field, data) { 
    user.data[field] = data; 
}; 

userService.clearDataField = function(field) { 
    delete user.data[field]; 
}; 

userService.pushData = function(key, data) { 
    if (typeof(key) === 'string') { 
     user.data[key] = data; 
    } else { 
     _.reduce(key, function(obj, child, index, list) { 
      obj[child] = obj[child] || {}; 

      if (index == list.length-1) { 
       obj[child] = data; 
      } 

      return obj[child]; 
     }, user.data);   
    } 
}; 

userService.deleteData = function(key) { 
    if (typeof(key) === 'string') { 
     delete user.data[key]; 
    } else { 
     _.reduce(key, function(obj, child, index, list) { 
      obj[child] = obj[child] || {}; 

      if (index == list.length-1) { 
       delete obj[child]; 
       return; 
      } 

      return obj[child]; 
     }, user.data);   
    } 
}; 

return userService; 
}); 
0

Innym rozwiązaniem, które działa na mnie:

account.service.js

(function() { 
    'use strict'; 

    angular 
     .module('app.account') 
     .factory('Account', Account); 

    Account.$inject = [ 
     '$firebaseAuth', 
     '$firebaseObject' 
    ]; 

    /* @ngInject */ 
    function Account(
     $firebaseAuth, 
     $firebaseObject, 
    ) { 
     var firebaseRef = new Firebase('https://<<-- MY_FIREBASE -->>.firebaseio.com'); 
     var authObj = $firebaseAuth(firebaseRef); 
     var service = { 
      userInfo: null 
     }; 
     activate(); 
     return service; 

     //////////////// 

     function activate() { 
      // Add listeners for authentication state changes 
      authObj.$onAuth(function(authData) { 
       if (authData) { 
        // Load the userInfo 
        loadUserInfo(authData); 
       } else { 
        // Destroy the userInfo Object if one exists 
        if (service.userInfo) { 
         service.userInfo.$destroy(); 
         service.userInfo = null; 
        } 
       } 
      }); 
     } 

     function loadUserInfo(authData) { 
      var userRef = firebaseRef.child('users').child(authData.uid); 
      var loadedInfo = $firebaseObject(userRef); 

      loadedInfo.$loaded() 
      .then(function() { 
       service.userInfo = loadedInfo; 
      }) 
      .catch(function(error) { 
       switch (error.code) { 
        case 'PERMISSION_DENIED': 
         alert('You don\'t have the permission to see that data.'); 
         break; 
        default: 
         alert('Couldn\'t load the user info.'); 
       } 
      }); 
     } 
    } 
})(); 

pewne-component.controller.js

(function() { 
    'use strict'; 

    angular 
     .module('app') 
     .controller('SomeController', SomeController); 

    SomeController.$inject = [ 
     'Account' 
    ]; 

    /* @ngInject */ 
    function SomeController(
     Account 
    ) { 
     var vm = this; 

     vm.userInfo  = userInfo; 

     //////////////// 

     function userInfo() { 
      return Account.userInfo; 
     } 

     ... 
    } 
})(); 

niektóre jednoskładnikowy. html

... 
<div class="user-id"> 
    {{vm.userInfo().id}} 
<div> 
...