2014-01-21 1 views
31

Ich möchte ein Beispiel für die Authentifizierung und Autorisierung in einer SPA-angularjs-Anwendung mit asp.net MVC Webapi als Back-End-und Client-Seiten-Routing (keine cshtml) erstellen. Im Folgenden finden Sie ein Beispiel für Funktionen, die zum Einrichten des vollständigen Beispiels verwendet werden können. Aber ich kann das alles nicht zusammensetzen. Jede Hilfe wird geschätzt.AngularJS clientside Routing und Token-Authentifizierung mit Webapi

Fragen:

  1. Was best practice ist: Plätzchen oder Token basiert?
  2. Wie erstelle ich das Bearer-Token in eckigen, um bei jeder Anfrage zu autorisieren?
  3. Validierung der API-Funktionen?
  4. Wie behalte ich den Benutzernamen, den der Benutzer auf dem Client angemeldet hat?

Beispielcode:

  1. Anmelden Form

    <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 Winkelregler

    $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. Meine 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. Authorization die JWT-Bibliothek verwendet für Inhalte zu beschränken.

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

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

Antwort

89

Ob Cookie-Authentifizierung oder (Träger) verwenden Token hängt noch von der Art der Anwendung, die Sie haben. 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 nicht mit ASP.NET helfen, aber normalerweise JWT-Bibliotheken erzeugen und verifizieren das Token für Sie. Alles, was Sie tun müssen, ist generate oder encode auf die Anmeldeinformationen (und das Geheimnis) und verify oder decode auf dem Token mit jeder Anfrage gesendet. Und Sie müssen keinen Zustand auf dem Server speichern und müssen kein Cookie senden, was Sie wahrscheinlich mit FormsAuthentication.SetAuthCookie(user.UserName, false) getan haben.

Ich bin sicher, dass Ihre Bibliothek ein Beispiel für die Verwendung von Generate/Encode und Verify/Decode Tokens bietet.

So zu generieren und zu überprüfen ist nicht etwas, was Sie auf der Client-Seite tun.

Der Fluss geht in etwa so:

  1. Client sendet die Benutzer an den Server-Anmeldeinformationen zur Verfügung gestellt.
  2. Der Server authentifiziert Anmeldeinformationen und antwortet mit einem generierten Token.
  3. Client speichert das Token irgendwo (lokaler Speicher, Cookies oder nur im Speicher).
  4. Client sendet das Token als Autorisierungsheader bei jeder Anforderung an den Server.
  5. Server überprüft das Token und handelt entsprechend mit dem Senden der angeforderten Ressource oder einer 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 hält die Daten so lange, wie der Benutzer die Seite geöffnet hat. Wenn Sie die Ablaufzeiten selbst verwalten möchten, können Sie stattdessen localStorage verwenden. Die Schnittstelle ist dieselbe.

Schritt 4:

Um das Token bei jeder Anfrage an den Server zu senden, können Sie verwenden, was Angular ein Interceptor nennt. Alles, was Sie tun müssen, ist die zuvor gespeicherte Token (falls vorhanden) erhalten und es 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, immer SSL zu verwenden!

+0

Das ist wirklich eine großartige Erklärung, genau das, was ich gesucht habe. Vielen Dank für die Antworten und detaillierte Beispiele. –

+0

Sicher, froh, dass ich helfen konnte :) – bernhardw

+0

Gibt es trotzdem eine Aktualisierung des Zugriffstokens durch einen versteckten i-Frame (vorausgesetzt, der Authentifizierungsserver erinnert sich an seine vorherige Berechtigung)? – g18c