19

Come creare un proprio servizio accessibile a livello globale che chiamerà il server entro il currentUser() solo una volta al caricamento della pagina, se l'utente è connesso, conservarlo e fornire dati ai controller o agli stati fino al logout? Ora mi sto risolvendo molte volte in molti stati o controller currentUser(), ho trovato nei documenti: authparseresponse che è possibile fare il proprio servizio, ma non so come gestirlo nel modo giusto.Come mantenere l'utente corrente globale fino al logout con angular_devise?

esempio in ui-router Ho due chiamate al server, sarebbe sufficiente solo quando la pagina viene caricata:

.state('login', { 
    url: '/login', 
    templateUrl: 'auth/_login.html', 
    controller: 'AuthCtrl', 
    onEnter: [ 
    '$state', 'Auth', 
    function($state, Auth) { 
     Auth.currentUser().then(function() { 
     $state.go('home'); 
     }); 
    } 
    ] 
}) 
.state('dashboard', { 
    url: '/dashboard', 
    templateUrl: 'dashboard.html', 
    onEnter: [ 
    '$state', 'Auth', 
    function($state, Auth) { 
     Auth.currentUser().then(function(user) {}, function(err) { 
     $state.go('home');// user not logged in 
     }); 
    } 
    ] 
}) 

o ogni volta successiva chiamata del server in NavController:

app.controller('NavController', [ 
    '$state', '$scope', 'Auth', function($state, $scope, Auth) { 
    $scope.signedIn = Auth.isAuthenticated; 
    $scope.logout = Auth.logout; // logout function 
    Auth.currentUser().then(function(user) { 
     $scope.user = user; 
    }); 
    $scope.$on('devise:login', function(e, user) { 
     $scope.user = user; 
    }); 
    $scope.$on('devise:logout', function(e, user) { 
     $scope.user = {}; 
     $state.go("home"); 
    }); 
    } 
]); 

ho trovato domanda simile senza risposta: stackoverflow

+0

Avete il controllo del server di login back-end? Pubblicherò una soluzione per ciò che è facile e comune, ma richiede una funzione aggiuntiva lato server. –

+0

@FerTo Sto usando Ruby on Rails con [Devise gem] (https://github.com/plataformatec/devise), quindi volevo combinarlo senza dolore con [angular_devise] (https://github.com/ cloudspace/angular_devise). – luzny

+0

Oh ok, dovresti "ignorare" il mio codice. –

risposta

8

Ho dovuto occuparmi dell'autenticazione utente in una grande app Angolare e ho trovato questo articolo molto utile: https://medium.com/opinionated-angularjs/techniques-for-authentication-in-angularjs-applications-7bbf0346acec

specifico a 'come farlo accadere solo una volta':

  • è possibile chiamare l'init() del Servizio in un blocco app.run
  • aggiungendolo come requisito di un resolve stato esterno dell'app (se si utilizzano stati nidificati)

A UserService Il servizio per rappresentare lo stato di accesso dell'utente funziona bene per lo stato di condivisione in tutta l'applicazione. Le funzioni di accesso e disconnessione possono essere esposte attraverso questo servizio e anche i dettagli dell'utente possono essere memorizzati qui. Definire un UserApi che si estende $resource probabilmente aiuterà anche a separare i problemi di HTTP reali dalla gestione dello stato dell'utente.

Altre preoccupazioni che cattura voi, entrambi i quali sono coperti in questo articolo: stato persistente attraverso aggiornamenti di pagina, e con le aree del sito che sono accessibili solo quando l'utente è connesso a

11

come sappiamo. factory è un oggetto singleton e in pratica viene utilizzato per la condivisione dei dati. Possiamo iniettarlo su qualsiasi controller e funziona come dipendenza . Così anche questo potrebbe risolvere il tuo problema. iniettare questo servizio per il vostro blocco di determinazione dello Stato e verificare se esiste utente o meno se non poi chiamare la funzione utente prendere di fabbrica

app.factory("User", function($http, $q, $rootScope) { 
var user = null; 
return { 
    fetchUser: function() { 
     /*your ajax call that return current user*/ 
     user = YOUR_SERVER_RESPONSE; 
     return user; 

    }, 
    getUser : function(){ 
     return user; 
    }, 
    setUser : function(u){ 
     user = u; 
    } 
} 

});

e il tuo blocco config stato è assomigliare

.state('dashboard', { 
    url: '/dashboard', 
    templateUrl: 'dashboard.html', 
    resolve : function(User){ 
    if(User.getUser()){ 
     return User.getUser(); 
    }else{ 
     return User.fetchUser(); 
    } 
    } 
}) 
+0

Non voglio creare un nuovo servizio, quindi in questo caso questo è un concetto interessante per la cooperazione con 'angular_devise', se questo approccio può risolvere la promessa concatenata dal servizio 'Auth' tramite' User.fetchUser() 'in' ui-router ', Lo userò. – luzny

+0

@luzny di guardare nella mia risposta se si desidera solo verificare senza creare un nuovo servizio, basta usare il rootScope. Ho aggiunto esattamente la stessa soluzione prima. Come descrivi, vuoi solo controllare "on page load" e fornire le informazioni ad ogni altro servizio/controller. La soluzione più semplice è usare rootScope, ma preferirei l'uso di un servizio utente di base –

+0

@luzny sì, questo approccio sta funzionando molto bene nella promessa incatenata. Ho usato questo concetto è il mio progetto. risolvere ogni blocco può avere dipendenza del blocco precedente da risolvere per primo e funziona bene. Ho provato questo mentre si utilizza oclazyload e aggiornare APP. (Mentre lo stato corrente è 'N livello') –

1

ho risolto il problema delle informazioni current_user con angolare aggiungendo il seguente codice JavaScript (jQuery) al fondo della mia pagina HTML principale:

$("meta[name=current_user]").data('current_user', { 
    id: <%=j current_user.id.to_s %>, 
    username: "<%=j current_user.full_name.to_s %>" 
}); 

È possibile analizzare in qualsiasi informazione necessaria, questo sembra essere un progetto Rails e tutto quello che serviva era l'ID e NAME (con l'ID che potevo interrogare l'oggetto fabbrica Utente e ricevere un JSON con informazioni complete se necessario).

Poi, nel tuo AngularJS controller è possibile aggiungere (mio è CoffeeScript):

# Grab User Info 
current_user = angular.element("meta[name=current_user]").data 'current_user' 

# Stop Here if you Have the Info you Need 
$scope.user = current_user 

# **** OR Get More Info if User is Logged In 
if current_user.id is not undefined 
    $scope.user = User.get {id: current_user.id} 

Ecco il mio Code Factory per l'utente (CoffeeScript nuovo):

# In order to prevent minification from effecting the code 
# must wrap functions as arrays and pass in the variables as 
# strings before the function call 
app.factory "User", ["$resource", ($resource) -> 
    $resource("/api/angular/users/:id", 
    { id: "@id" }, 
    { 
     update: { method: "PUT" } 
    }) 
] 

Fammi sapere se avere domande

0

Salvare i dettagli dell'utente in Global.user utilizzare il modulo 'Globale' in controller o servizi.

quando si deve accedere l'utente quindi accedere utilizzando Global.user

1

Modifica: Modifica alcune parti per l'utilizzo con il modulo angular_device

In generale, sto usando la soluzione fornita qui (https://vickev.com/#!/article/authentication-in-single-page-applications-node-js-passportjs-angularjs) che descrive come verificare se un utente ha effettuato l'accesso per ogni chiamata HTTP.

Controllare il carico, se l'utente è loggato

myApp.config(['$routeProvider','$locationProvider', 
function($routeProvider, $locationProvider) { 
//================================================ 
// Check if the user is connected 
//================================================ 
var checkLoggedin = function($q, $rootScope, Auth, User){ 
    // Initialize a new promise 
    var deferred = $q.defer(); 
    Auth.currentUser().then(function(userObj){ 
    deferred.resolve(); 
    //option a: just save the user object into the $rootScope 
    $rootScope.User = userObj; 
    //option b: create a factory 'User' and a method 'save()' which parses the JSON returned from your Server 
    User.save(userObj); 
    }, function(error){ 
    deferred.reject(); 
    }); 
    return deferred.promise; 
}; 


//================================================ 
// Define all the routes 
//================================================ 
$routeProvider 
    //Start page, where the user gets a list of registered SO and can add new ones 
    .when('/', { 
    templateUrl: 'templates/index.html', 
    controller: 'indexCtrl', 
    resolve: { 
     loggedin: checkLoggedin 
    } 
    }) 
    .when('/login', { 
    templateUrl: 'templates/login.html', 
    controller: 'loginCtrl' 
    }) 
    // do more here 
    .otherwise({ 
     redirectTo: '/' 
    }); 
}]).run(function($rootScope, $http){ 
//Do some initial tasks or set some values 
}); 

vorrei creare un servizio aggiuntivo denominato "utente" (come i servizi sono single), definire alcuni metodi, per esempio save() e get(), per salvare l'utente nel servizio singleton e arrivare a restituirlo dove è necessario. Con la funzione "checkLoggedIn" è possibile definire un'opzione di "risoluzione" per i percorsi e se la promessa viene risolta l'utente è in grado di accedere alla pagina riservata.