AngularJS: Grundlegendes Beispiel für die Verwendung der Authentifizierung in Einzelseitenanwendungen


100

Ich bin neu bei AngularJS und habe ihr Tutorial durchgesehen und ein Gefühl dafür bekommen.

Ich habe ein Backend für mein Projekt bereit, wo jeder der REST Endpunkte authentifiziert werden muss.

Was ich tun möchte
a.) Ich möchte eine einzelne Seite für mein Projekt haben http://myproject.com.
b.) Sobald ein Benutzer die URL im Browser eingibt, je nachdem, ob der Benutzer angemeldet ist oder nicht, wird ihm eine Startseite / Ansicht oder eine Anmeldeseite / Ansicht unter derselben URL angezeigt http://myproject.com.
c.) Wenn ein Benutzer nicht angemeldet ist, füllt er das Formular aus und der Server legt eine USER_TOKENIn-Sitzung fest, sodass alle weiteren Anforderungen an Endpunkte basierend auf authentifiziert werdenUSER_TOKEN

Meine Verwirrungen
a.) Wie kann ich mit der clientseitigen Authentifizierung mit AngularJS umgehen? Ich habe hier und hier gesehen , aber nicht verstanden, wie man sie verwendet.
B.) Wie kann ich dem Benutzer verschiedene Ansichten präsentieren, je nachdem, ob der Benutzer angemeldet ist oder nicht unter derselben URLhttp://myproject.com

Ich benutze angular.js zum ersten Mal und bin wirklich verwirrt, wie ich anfangen soll. Alle Ratschläge und / oder Ressourcen werden sehr geschätzt.


Bitte werfen Sie einen Blick auf den folgenden Artikel frederiknakstad.com/…
Ajay Beniwal

1
@MichaelCalkins nur einen Link zu platzieren ist nicht konstruktiv. Sie sollten zumindest sagen, was der Link bieten wird.
Dave Gordon

Mein b: AngularJS Zugriffskontrolle und Authentifizierung coderwall.com/p/f6brkg
Michael J. Calkins

Das Team von OAuth hat eine großartige Bibliothek für diesen andreareginato.github.io/oauth-ng
Faktor 10

Antworten:


48

Ich habe ein Github-Repo erstellt, das diesen Artikel im Wesentlichen zusammenfasst: https://medium.com/opinionated-angularjs/techniques-for-authentication-in-angularjs-applications-7bbf0346acec

ng-login Github repo

Plunker

Ich werde versuchen, es so gut wie möglich zu erklären. Ich hoffe, ich helfe einigen von Ihnen da draußen:

(1) app.js: Erstellung von Authentifizierungskonstanten für die App-Definition

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) Auth-Dienst: Alle folgenden Funktionen sind im auth.js-Dienst implementiert. Der $ http-Dienst wird verwendet, um mit dem Server für die Authentifizierungsverfahren zu kommunizieren. Enthält auch Funktionen zur Autorisierung, dh wenn der Benutzer eine bestimmte Aktion ausführen darf.

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) Sitzung: Ein Singleton zum Speichern von Benutzerdaten. Die Implementierung hier hängt von Ihnen ab.

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) Übergeordneter Controller: Betrachten Sie dies als die "Haupt" -Funktion Ihrer Anwendung, alle Controller erben von diesem Controller und es ist das Rückgrat der Authentifizierung dieser App.

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

(5) Zugangskontrolle: Um den Zugang auf bestimmten Routen zu verweigern, müssen 2 Schritte ausgeführt werden:

a) Fügen Sie im $ stateProvider-Dienst des UI-Routers Daten zu den Rollen hinzu, die für den Zugriff auf jede Route zulässig sind (siehe unten) (dies gilt auch für ngRoute).

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

b) Fügen Sie unter $ rootScope. $ on ('$ stateChangeStart') die Funktion hinzu, um eine Statusänderung zu verhindern, wenn der Benutzer nicht autorisiert ist.

$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) Auth Interceptor: Dies ist implementiert, kann jedoch nicht auf den Umfang dieses Codes überprüft werden. Nach jeder $ http-Anforderung überprüft dieser Interceptor den Statuscode. Wenn einer der folgenden Codes zurückgegeben wird, sendet er ein Ereignis, um den Benutzer zu zwingen, sich erneut anzumelden.

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 Ein Fehler beim automatischen Ausfüllen der Formulardaten, wie im ersten Artikel angegeben, kann leicht vermieden werden, indem die in directives.js enthaltene Direktive hinzugefügt wird.

PS2 Dieser Code kann vom Benutzer leicht angepasst werden, um verschiedene Routen anzuzeigen oder Inhalte anzuzeigen, die nicht angezeigt werden sollten. Die Logik MUSS serverseitig implementiert werden. Dies ist nur eine Möglichkeit, die Dinge in Ihrer ng-App richtig darzustellen.


1
Ich bin Ihrem Leitfaden gefolgt, um mich mit der clientseitigen Logik zu beschäftigen. Es ist sehr gut!! Ich habe etwas über das manuelle Zerstören von Sitzungen verpasst, aber wir müssen auch experimentieren und Dinge kaputt machen!
Sebastialonso

~~ nicht sicher, ob ich diese Zeile richtig verstehe: Diese authService.login() = [...]eckigen Klammern stehen für so etwas wie $http.get(url, {uID, pwd}? ~~ ok, schaute in den Plunker, es war wie gesagt XD
Netalex

1
Können Sie Ihre Antwort für die Serverseite erweitern?
Abfrage

25

Ich mag den Ansatz und habe ihn serverseitig implementiert, ohne authentifizierungsbezogene Dinge im Front-End zu tun

Meine 'Technik' in meiner neuesten App ist .. der Client kümmert sich nicht um Auth. Für jede einzelne Sache in der App ist zuerst eine Anmeldung erforderlich, sodass der Server nur immer eine Anmeldeseite bereitstellt, es sei denn, in der Sitzung wird ein vorhandener Benutzer erkannt. Wenn session.user gefunden wird, sendet der Server nur index.html. Bam: -o

Suchen Sie nach dem Kommentar von "Andrew Joslin".

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


3
ob es eine Web-API ist? Ich habe Ihre Antwort nicht bekommen, denke ich :(
Leandro De Mello Fagundes

1
Was ist, wenn Sie den Benutzernamen anzeigen möchten? Oder wenn Sie mit einem Dienst mit dem Benutzernamen in den Endpunkt-URLs sprechen?
Perrygeo

2
Entschuldigung, aber ich verstehe die Antwort nicht. Wie gehst du mit der Sitzung im Winkel um? Wo ist session.user eingestellt? Könnten Sie bitte ein Codebeispiel dafür machen? Vielen Dank
François Romain

4
Die Sitzungen werden auf Clientseite und nicht auf Serverseite abgewickelt. Der Client speichert das Token und sendet es als Teil jeder von ihm gestellten Anforderung. Der Server validiert das Token und verarbeitet die Anfrage
Tagträumer

4
Könnte jemand, der es versteht, diese Antwort bitte für den Rest von uns bearbeiten?
Alojz Janez

14

Ich habe hier eine ähnliche Frage beantwortet: AngularJS Authentication + RESTful API


Ich habe ein AngularJS-Modul für UserApp geschrieben , das geschützte / öffentliche Routen, das Umleiten beim Anmelden / Abmelden, Herzschläge , das Speichern des Sitzungstokens in einem Cookie, Ereignisse usw. unterstützt.

Sie könnten entweder:

  1. Ändern Sie das Modul und hängen Sie es an Ihre eigene API an, oder
  2. Verwenden Sie das Modul zusammen mit UserApp (einer Cloud-basierten Benutzerverwaltungs-API).

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

Wenn Sie UserApp verwenden, müssen Sie keinen serverseitigen Code für das Benutzermaterial schreiben (mehr als das Überprüfen eines Tokens). Nehmen Sie an dem Codecademy-Kurs teil , um ihn auszuprobieren.

Hier sind einige Beispiele, wie es funktioniert:

  • So legen Sie fest, welche Routen öffentlich sein sollen und welche Route das Anmeldeformular ist:

    $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'});

    Die .otherwise()Route sollte so eingestellt sein, dass Ihre Benutzer nach der Anmeldung umgeleitet werden sollen. Beispiel:

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

  • Anmeldeformular mit Fehlerbehandlung:

    <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>
  • Anmeldeformular mit Fehlerbehandlung:

    <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>
  • Abmeldelink:

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

    (Beendet die Sitzung und leitet zur Anmelderoute weiter.)

  • Zugriff auf Benutzereigenschaften:

    Auf Benutzereigenschaften wird über den userDienst zugegriffen , z.user.current.email

    Oder in der Vorlage: <span>{{ user.email }}</span>

  • Elemente ausblenden, die nur sichtbar sein sollen, wenn Sie angemeldet sind:

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

  • Zeigen Sie ein Element basierend auf Berechtigungen an:

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

user.token()Um sich bei Ihren Back-End-Diensten zu authentifizieren, rufen Sie einfach das Sitzungstoken ab und senden Sie es mit der AJAX-Anforderung. Verwenden Sie im Back-End die UserApp-API (wenn Sie UserApp verwenden), um zu überprüfen, ob das Token gültig ist oder nicht.

Wenn Sie Hilfe benötigen, lassen Sie es mich einfach wissen!


Wie würde ich "das Modul ändern und an Ihre eigene API anhängen" ?
Pureferret

2

In anglejs können Sie den UI-Teil, den Dienst, die Anweisungen und den gesamten Teil von anglejs erstellen, der die UI darstellt. Es ist eine schöne Technologie, an der man arbeiten kann.

Als jeder, der neu in dieser Technologie ist und den "Benutzer" authentifizieren möchte, schlage ich vor, dies mit der Leistung von c # web api zu tun. Dazu können Sie die OAuth-Spezifikation verwenden, mit deren Hilfe Sie einen starken Sicherheitsmechanismus zur Authentifizierung des Benutzers aufbauen können. Sobald Sie das WebApi mit OAuth erstellt haben, müssen Sie diese API als Token aufrufen:

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;
 
    };
 

Sobald Sie das Token erhalten haben, fordern Sie mithilfe von Token die Ressourcen von anglejs an und greifen auf die Ressource zu, die in der Web-API mit OAuth-Spezifikation sicher ist.

Weitere Informationen finden Sie im folgenden Artikel: -

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


1

Ich denke, dass jede JSON-Antwort eine Eigenschaft enthalten sollte (z. B. {authenticated: false}) und der Client sie jedes Mal testen muss: Wenn false, wird der Angular-Controller / -Dienst zur Anmeldeseite "umleiten".

Und was passiert, wenn der Benutzer de JSON abfängt und den Bool in True ändert?

Ich denke, Sie sollten sich niemals auf die Kundenseite verlassen, um solche Dinge zu tun. Wenn der Benutzer nicht authentifiziert ist, sollte der Server nur zu einer Anmelde- / Fehlerseite umleiten.


2
Überprüfen Sie Folgendes : github.com/witoldsz/angular-http-auth - Der Interceptor sucht nach dem Statuscode der Serverantwort und sendet ein Ereignis, wenn es 403 ('Anmeldung erforderlich') ist, damit Sie es in der App abfangen und das Anmeldefeld anzeigen können.
Aherok

10
Hören Sie auf, sich gegenseitig mit Antworten zu antworten. Dafür sind die Kommentare da!
Soviut

@ aherok Vorschlag, Ihr Kommentar sollte zu einer Antwort befördert werden, er wird rechtzeitig an die Spitze gewählt. Der Rest ist nur Lärm.
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;
 
    };
 

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.