it-swarm.com.de

Client-seitiges AngularJS-Routing und Token-Authentifizierung mit Web-API

Ich möchte ein Beispiel für die Authentifizierung und Autorisierung in einer SPA anglejs-Anwendung mit asp.net mvc webapi als Backend und clientseitigem Routing (ohne cshtml) erstellen. Im Folgenden finden Sie nur ein Beispiel für Funktionen, mit denen das vollständige Beispiel eingerichtet werden kann. Aber ich kann einfach nicht alles zusammenfassen. Jede Hilfe dankbar.

Fragen:

  1. Was ist die beste Vorgehensweise: Cookie- oder Token-basiert?
  2. Wie erstelle ich das Inhaber-Token in angular), um es bei jeder Anforderung zu autorisieren?
  3. Validierung von API-Funktionen?
  4. Wie behalte ich die auf dem Client als Benutzer angemeldete Authentifizierung bei?

Beispielcode:

  1. Anmeldeformular

    <form name="form" novalidate>
     <input type="text" ng-model="user.userName" />
     <input type="password" ng-model="user.password" />
     <input type="submit" value="Sign In" data-ng-click="signin(user)">
    </form>
    
  2. Authentifizierung Angular Controller

    $scope.signin = function (user) {
    $http.post(uri + 'account/signin', user)
        .success(function (data, status, headers, config) {
            user.authenticated = true;
            $rootScope.user = user;
            $location.path('/');
        })
        .error(function (data, status, headers, config) {
    
            alert(JSON.stringify(data));
            user.authenticated = false;
            $rootScope.user = {};
        });
    };
    
  3. Mein API-Backend-API-Code.

    [HttpPost]
    public HttpResponseMessage SignIn(UserDataModel user)
    {
        //FormsAuthetication is just an example. Can I use OWIN Context to create a session and cookies or should I just use tokens for authentication on each request? How do I preserve the autentication signed in user on the client?
        if (this.ModelState.IsValid)
        {
            if (true) //perform authentication against db etc.
            {
                var response = this.Request.CreateResponse(HttpStatusCode.Created, true);
                FormsAuthentication.SetAuthCookie(user.UserName, false);
    
                return response;
            }
    
            return this.Request.CreateErrorResponse(HttpStatusCode.Forbidden, "Invalid username or password");
        }
        return this.Request.CreateErrorResponse(HttpStatusCode.BadRequest, this.ModelState);
    }
    
  4. Autorisierung Verwenden der JWT-Bibliothek zum Einschränken von Inhalten.

    config.MessageHandlers.Add(new JsonWebTokenValidationHandler
    {
      Audience = "123",
      SymmetricKey = "456"
    });
    
  5. Meine API-Methoden

    [Authorize]
    public IEnumerable<string> Get()
    {
     return new string[] { "value1", "value2" };
    }
    
32

Ob Sie die Cookie-Authentifizierung oder (Inhaber-) Token verwenden, hängt immer noch vom App-Typ ab. Und soweit ich weiß, gibt es noch keine Best Practice. Da Sie jedoch an einem SPA arbeiten und bereits eine JWT-Bibliothek verwenden, würde ich den tokenbasierten Ansatz bevorzugen.

Leider kann ich Ihnen bei ASP.NET nicht helfen, aber normalerweise generieren und überprüfen JWT-Bibliotheken das Token für Sie. Sie müssen lediglich generate oder encode für die Anmeldeinformationen (und das Geheimnis) und verify oder decode für das Token aufrufen, das mit jeder Anforderung gesendet wird. Und Sie müssen keinen Status auf dem Server speichern und kein Cookie senden, was Sie wahrscheinlich mit FormsAuthentication.SetAuthCookie(user.UserName, false) getan haben.

Ich bin sicher, Ihre Bibliothek enthält ein Beispiel für die Verwendung von Token zum Generieren/Codieren und Überprüfen/Decodieren.

Das Generieren und Überprüfen ist also nichts, was Sie auf der Clientseite tun.

Der Ablauf sieht ungefähr so ​​aus:

  1. Der Client sendet die vom Benutzer angegebenen Anmeldeinformationen an den Server.
  2. Der Server authentifiziert die Anmeldeinformationen und antwortet mit einem generierten Token.
  3. Der Client speichert das Token irgendwo (lokaler Speicher, Cookies oder nur im Speicher).
  4. Der Client sendet das Token bei jeder Anforderung als Autorisierungsheader an den Server.
  5. Der Server überprüft das Token und sendet dementsprechend entweder die angeforderte Ressource oder eine 401 (oder etwas Ähnliches).

Schritt 1 und 3:

app.controller('UserController', function ($http, $window, $location) {
    $scope.signin = function(user) {
    $http.post(uri + 'account/signin', user)
        .success(function (data) {
            // Stores the token until the user closes the browser window.
            $window.sessionStorage.setItem('token', data.token);
            $location.path('/');
        })
        .error(function () {
            $window.sessionStorage.removeItem('token');
            // TODO: Show something like "Username or password invalid."
        });
    };
});

sessionStorage speichert die Daten, solange der Benutzer die Seite geöffnet hat. Wenn Sie die Ablaufzeiten selbst verwalten möchten, können Sie stattdessen localStorage verwenden. Die Schnittstelle ist die gleiche.

Schritt 4:

Um das Token bei jeder Anfrage an den Server zu senden, können Sie verwenden, was Angular ein Interceptor aufruft. Sie müssen nur das zuvor gespeicherte Token abrufen (falls vorhanden) ) und als Header an alle ausgehenden Anfragen anhängen:

app.factory('AuthInterceptor', function ($window, $q) {
    return {
        request: function(config) {
            config.headers = config.headers || {};
            if ($window.sessionStorage.getItem('token')) {
                config.headers.Authorization = 'Bearer ' + $window.sessionStorage.getItem('token');
            }
            return config || $q.when(config);
        },
        response: function(response) {
            if (response.status === 401) {
                // TODO: Redirect user to login page.
            }
            return response || $q.when(response);
        }
    };
});

// Register the previously created AuthInterceptor.
app.config(function ($httpProvider) {
    $httpProvider.interceptors.Push('AuthInterceptor');
});

Und stellen Sie sicher, dass Sie immer SSL verwenden!

91
bernhardw