AngularJS: esempio di base per utilizzare l'autenticazione nell'applicazione a pagina singola


100

Sono nuovo su AngularJS e ho seguito il loro tutorial e ne ho avuto un'idea.

Ho pronto un back-end per il mio progetto in cui ciascuno degli RESTendpoint deve essere autenticato.

Cosa voglio fare
a.) Voglio avere un'unica pagina per il mio progetto http://myproject.com.
b.) Una volta che un utente raggiunge l'URL nel browser, in base al fatto che l'utente sia loggato o meno, gli viene presentata una home page / vista o una pagina / vista di accesso sotto lo stesso URL http://myproject.com.
c.) se un utente non è connesso, compila il modulo e il server imposta una USER_TOKENsessione in, quindi tutte le ulteriori richieste agli endpoint verranno autenticate in base aUSER_TOKEN

Le mie confusioni
a.) Come posso gestire l'autenticazione lato client utilizzando AngularJS? Ho visto qui e qui ma non ho capito come usarli
b.) Come posso presentare diverse visualizzazioni all'utente in base al fatto che l'utente sia loggato o meno sotto lo stesso URLhttp://myproject.com

Sto usando angular.js per la prima volta e mi sto davvero confondendo su come iniziare. Eventuali consigli e / o risorse sono molto apprezzati.


Dai

1
@MichaelCalkins solo il posizionamento di un collegamento non è costruttivo. Dovresti almeno dire cosa fornirà il collegamento.
Dave Gordon,

My b: AngularJS Access Control and Authentication coderwall.com/p/f6brkg
Michael J. Calkins,

Il team di OAuth ha un'ottima libreria per questo andreareginato.github.io/oauth-ng
Faktor 10

Risposte:


48

Ho creato un repository GitHub riassumendo fondamentalmente questo articolo: https://medium.com/opinionated-angularjs/techniques-for-authentication-in-angularjs-applications-7bbf0346acec

ng-login Github repo

Plunker

Cercherò di spiegare il più bene possibile, spero di aiutare alcuni di voi là fuori:

(1) app.js: creazione di costanti di autenticazione sulla definizione dell'app

var loginApp = angular.module('loginApp', ['ui.router', 'ui.bootstrap'])
/*Constants regarding user login defined here*/
.constant('USER_ROLES', {
    all : '*',
    admin : 'admin',
    editor : 'editor',
    guest : 'guest'
}).constant('AUTH_EVENTS', {
    loginSuccess : 'auth-login-success',
    loginFailed : 'auth-login-failed',
    logoutSuccess : 'auth-logout-success',
    sessionTimeout : 'auth-session-timeout',
    notAuthenticated : 'auth-not-authenticated',
    notAuthorized : 'auth-not-authorized'
})

(2) Servizio di autenticazione : tutte le seguenti funzioni sono implementate nel servizio auth.js. Il servizio $ http viene utilizzato per comunicare con il server per le procedure di autenticazione. Contiene anche funzioni sull'autorizzazione, ovvero se l'utente è autorizzato a eseguire una determinata azione.

angular.module('loginApp')
.factory('Auth', [ '$http', '$rootScope', '$window', 'Session', 'AUTH_EVENTS', 
function($http, $rootScope, $window, Session, AUTH_EVENTS) {

authService.login() = [...]
authService.isAuthenticated() = [...]
authService.isAuthorized() = [...]
authService.logout() = [...]

return authService;
} ]);

(3) Sessione: un singleton per conservare i dati dell'utente. L'implementazione qui dipende da te.

angular.module('loginApp').service('Session', function($rootScope, USER_ROLES) {

    this.create = function(user) {
        this.user = user;
        this.userRole = user.userRole;
    };
    this.destroy = function() {
        this.user = null;
        this.userRole = null;
    };
    return this;
});

(4) Controller principale: considera questa come la funzione "principale" della tua applicazione, tutti i controller ereditano da questo controller ed è la spina dorsale dell'autenticazione di questa app.

<body ng-controller="ParentController">
[...]
</body>

(5) Controllo di accesso: per negare l'accesso su determinate rotte è necessario implementare 2 passaggi:

a) Aggiungere i dati dei ruoli autorizzati ad accedere a ciascuna route, sul servizio $ stateProvider del router ui come si può vedere di seguito (lo stesso può funzionare per ngRoute).

.config(function ($stateProvider, USER_ROLES) {
  $stateProvider.state('dashboard', {
    url: '/dashboard',
    templateUrl: 'dashboard/index.html',
    data: {
      authorizedRoles: [USER_ROLES.admin, USER_ROLES.editor]
    }
  });
})

b) In $ rootScope. $ on ('$ stateChangeStart') aggiungere la funzione per impedire il cambiamento di stato se l'utente non è autorizzato.

$rootScope.$on('$stateChangeStart', function (event, next) {
    var authorizedRoles = next.data.authorizedRoles;
    if (!Auth.isAuthorized(authorizedRoles)) {
      event.preventDefault();
      if (Auth.isAuthenticated()) {
        // user is not allowed
        $rootScope.$broadcast(AUTH_EVENTS.notAuthorized);
      } else {
        // user is not logged in
        $rootScope.$broadcast(AUTH_EVENTS.notAuthenticated);
      }
    }
});

(6) Interceptor di autenticazione: è implementato, ma non può essere verificato sull'ambito di questo codice. Dopo ogni richiesta $ http, questo intercettore controlla il codice di stato, se viene restituito uno dei seguenti, quindi trasmette un evento per costringere l'utente ad accedere nuovamente.

angular.module('loginApp')
.factory('AuthInterceptor', [ '$rootScope', '$q', 'Session', 'AUTH_EVENTS',
function($rootScope, $q, Session, AUTH_EVENTS) {
    return {
        responseError : function(response) {
            $rootScope.$broadcast({
                401 : AUTH_EVENTS.notAuthenticated,
                403 : AUTH_EVENTS.notAuthorized,
                419 : AUTH_EVENTS.sessionTimeout,
                440 : AUTH_EVENTS.sessionTimeout
            }[response.status], response);
            return $q.reject(response);
        }
    };
} ]);

PS Un bug con la compilazione automatica dei dati del modulo come indicato nel primo articolo può essere facilmente evitato aggiungendo la direttiva inclusa in directives.js.

PS2 Questo codice può essere facilmente modificato dall'utente, per consentire la visualizzazione di percorsi diversi o per visualizzare contenuti che non dovevano essere visualizzati. La logica DEVE essere implementata lato server, questo è solo un modo per mostrare le cose correttamente sulla tua ng-app.


1
Ho seguito la tua guida per addentrarmi nella logica lato client. È molto buono!! Mi sono perso qualcosa sulla distruzione manuale delle sessioni, ma dobbiamo anche sperimentare e rompere le cose!
Sebastialonso

~~ non sono sicuro di aver capito correttamente quella linea: authService.login() = [...]quelle parentesi quadre staranno per qualcosa del genere $http.get(url, {uID, pwd}? ~~ ok, ho guardato nel plunker, era come ho detto XD
netalex

1
puoi espandere la tua risposta per lato server?
interrogazione

25

Mi piace l'approccio e l'ho implementato sul lato server senza eseguire alcuna operazione relativa all'autenticazione sul front-end

La mia "tecnica" sulla mia ultima app è ... al cliente non interessa Auth. Ogni singola cosa nell'app richiede prima un accesso, quindi il server serve sempre una pagina di accesso a meno che un utente esistente non venga rilevato nella sessione. Se viene trovato session.user, il server invia semplicemente index.html. Bam: -o

Cerca il commento di "Andrew Joslin".

https://groups.google.com/forum/?fromgroups=#!searchin/angular/authentication/angular/POXLTi_JUgg/VwStpoWCPUQJ


3
se è un'API web? Immagino di non aver ricevuto la tua risposta :(
Leandro De Mello Fagundes

1
Cosa succede se si desidera visualizzare il nome utente? O se stai parlando a un servizio con il nome utente negli URL dell'endpoint?
perrygeo

2
scusa, ma non capisco la risposta. come gestisci la seduta in angolare? dov'è impostato session.user? potresti fare un esempio in codice di questo per favore? grazie
François Romain

4
Le sessioni vengono gestite sul lato client e non sul lato server, il client salva il token e lo invia come parte di ogni richiesta che fa. Il server convalida il token ed elabora la richiesta
daydreamer

4
Qualcuno che lo capisce potrebbe modificare questa risposta per il resto di noi, per favore?
Alojz Janez

14

Ho risposto a una domanda simile qui: AngularJS Authentication + RESTful API


Ho scritto un modulo AngularJS per UserApp che supporta percorsi protetti / pubblici, reindirizzamento su login / logout, heartbeat per controlli di stato, memorizza il token di sessione in un cookie, eventi, ecc.

Potresti:

  1. Modifica il modulo e collegalo alla tua API o
  2. Usa il modulo insieme a UserApp (un'API di gestione degli utenti basata su cloud)

https://github.com/userapp-io/userapp-angular

Se usi UserApp, non dovrai scrivere alcun codice lato server per le cose dell'utente (più che convalidare un token). Segui il corso su Codecademy per provarlo.

Ecco alcuni esempi di come funziona:

  • Come specificare quali percorsi devono essere pubblici e quale percorso è il modulo di accesso:

    $routeProvider.when('/login', {templateUrl: 'partials/login.html', public: true, login: true});
    $routeProvider.when('/signup', {templateUrl: 'partials/signup.html', public: true});
    $routeProvider.when('/home', {templateUrl: 'partials/home.html'});

    Il .otherwise()percorso dovrebbe essere impostato nel punto in cui desideri che i tuoi utenti vengano reindirizzati dopo il login. Esempio:

    $routeProvider.otherwise({redirectTo: '/home'});

  • Modulo di accesso con gestione degli errori:

    <form ua-login ua-error="error-msg">
        <input name="login" placeholder="Username"><br>
        <input name="password" placeholder="Password" type="password"><br>
        <button type="submit">Log in</button>
        <p id="error-msg"></p>
    </form>
  • Modulo di registrazione con gestione degli errori:

    <form ua-signup ua-error="error-msg">
      <input name="first_name" placeholder="Your name"><br>
      <input name="login" ua-is-email placeholder="Email"><br>
      <input name="password" placeholder="Password" type="password"><br>
      <button type="submit">Create account</button>
      <p id="error-msg"></p>
    </form>
  • Collegamento di disconnessione:

    <a href="#" ua-logout>Log Out</a>

    (Termina la sessione e reindirizza al percorso di accesso)

  • Accedi alle proprietà utente:

    Si accede alle proprietà dell'utente utilizzando il userservizio, ad esempio:user.current.email

    O nel modello: <span>{{ user.email }}</span>

  • Nascondi elementi che dovrebbero essere visibili solo dopo aver effettuato l'accesso:

    <div ng-show="user.authorized">Welcome {{ user.first_name }}!</div>

  • Mostra un elemento in base alle autorizzazioni:

    <div ua-has-permission="admin">You are an admin</div>

E per autenticarti ai tuoi servizi di back-end, usa user.token()per ottenere il token di sessione e inviarlo con la richiesta AJAX. Sul back-end, utilizza l' API UserApp (se usi UserApp) per verificare se il token è valido o meno.

Se hai bisogno di aiuto, fammelo sapere!


Come faccio a "modificare il modulo e collegarlo alla tua API" ?
Pureferret

2

In angularjs puoi creare la parte dell'interfaccia utente, il servizio, le direttive e tutta la parte di angularjs che rappresentano l'interfaccia utente. È una bella tecnologia su cui lavorare.

Come chiunque sia nuovo in questa tecnologia e desideri autenticare l '"Utente", suggerisco di farlo con la potenza di c # web api. per questo puoi usare la specifica OAuth che ti aiuterà a costruire un potente meccanismo di sicurezza per autenticare l'utente. una volta creata la WebApi con OAuth, è necessario chiamare tale API per il token:

var _login = function (loginData) {
 
        var data = "grant_type=password&username=" + loginData.userName + "&password=" + loginData.password;
 
        var deferred = $q.defer();
 
        $http.post(serviceBase + 'token', data, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).success(function (response) {
 
            localStorageService.set('authorizationData', { token: response.access_token, userName: loginData.userName });
 
            _authentication.isAuth = true;
            _authentication.userName = loginData.userName;
 
            deferred.resolve(response);
 
        }).error(function (err, status) {
            _logOut();
            deferred.reject(err);
        });
 
        return deferred.promise;
 
    };
 

e una volta ottenuto il token, richiedi le risorse da angularjs con l'aiuto di Token e accedi alla risorsa che è stata mantenuta al sicuro nell'API web con le specifiche OAuth.

Si prega di dare un'occhiata al seguente articolo per ulteriore aiuto: -

http://bitoftech.net/2014/06/09/angularjs-token-authentication-using-asp-net-web-api-2-owin-asp-net-identity/


1

Penso che ogni risposta JSON dovrebbe contenere una proprietà (ad esempio {authenticated: false}) e il client deve testarla ogni volta: se false, il controller / servizio Angular "reindirizzerà" alla pagina di accesso.

E cosa succede se l'utente rileva de JSON e modifica il valore bool in True?

Penso che non dovresti mai fare affidamento sul lato client per fare questo genere di cose. Se l'utente non è autenticato, il server dovrebbe semplicemente reindirizzare a una pagina di accesso / errore.


2
Controlla questo: github.com/witoldsz/angular-http-auth : l'interceptor controlla il codice di stato della risposta del server e se è 403 ("login richiesto") trasmette un evento, quindi puoi catturarlo all'interno dell'app e visualizzare la casella di accesso.
aherok

10
Smetti di rispondervi l'un l'altro usando le risposte. Ecco a cosa servono i commenti!
Soviut

@ suggerimento aherok, il tuo commento dovrebbe essere promosso a una risposta, sarà votato tra i primi in tempo. il resto è solo rumore.
user237419

0

var _login = function (loginData) {
 
        var data = "grant_type=password&username=" + loginData.userName + "&password=" + loginData.password;
 
        var deferred = $q.defer();
 
        $http.post(serviceBase + 'token', data, { headers: { 'Content-Type': 'application/x-www-form-urlencoded' } }).success(function (response) {
 
            localStorageService.set('authorizationData', { token: response.access_token, userName: loginData.userName });
 
            _authentication.isAuth = true;
            _authentication.userName = loginData.userName;
 
            deferred.resolve(response);
 
        }).error(function (err, status) {
            _logOut();
            deferred.reject(err);
        });
 
        return deferred.promise;
 
    };
 

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.