2014-06-26 5 views
11

Ich habe eine Anwendung, die Spring Security für serverseitige Authentifizierung/Autorisierung, Spring MVC für die REST Server-Seite Endpunkte und AngularJS für Ansicht verwendet.Wie kann AngularJS oder eine andere Einzelseitenanwendung auf Basis von authentifizierten Benutzerrechten ordnungsgemäß versteckt/angezeigt werden?

Auf der Serverseite habe ich alle Filter implementiert, die für den Zugriff auf alle REST-Endpunkte erforderlich sind, basierend auf den Benutzerrechten. Meine Frage ist, wie soll ich mich wenden machen sichtbar/html Elemente, basierend auf den authentifizierten Benutzer Rechte versteckt?

Zum Beispiel habe ich in der Ansicht 3 Tasten (button1, button2, button3). Jede Taste hat eine entsprechende USER RIGHT, die sie sichtbar machen/verbergen sollte. Nennen wir diese Rechte USER_RIGHT1, USER_RIGHT2, USER_RIGHT3.

Wenn der Benutzer das Recht USER_RIGHT1 hat, soll er in der Ansicht sieht die button1, wenn er das Recht USER_RIGHT2 hat er die button2, und so weiter in der Ansicht sehen soll.

Mein Ansatz war eine Liste der authentifizierten Benutzerrechte auf dem Client zu haben, und etwas zu tun, wie das folgende Beispiel:

<div ng-if="rights contains USER_RIGHT1"> 
    <button name="button1".... /> 
</div> 
<div ng-if="rights contains USER_RIGHT2"> 
    <button name="button2".... /> 
</div> 

Ich bin nicht sicher, ob der authentifizierte Benutzer rechtse Liste in dem Client sein sollte .

Wie soll ich dieses Problem angehen? Mache ich es richtig?

Antwort

9

Sicherheit auf dem Client, d. H. In einem Browser ist neben nutzlos.Es sollte jedoch vorhanden sein, um den durchschnittlichen Benutzer daran zu hindern, etwas zu sehen, das sie nicht sollten, aber der Server sollte der ultimative Ort sein, an dem die Sicherheit ausgeführt wird.

Ich würde eine schnelle Anweisung erstellen, um die Komponenten show/hiding oder UI auszuführen und einen Authentifizierungsdienst zu haben, um die tatsächliche Logik zu bestimmen, ob der Benutzer die richtigen Rechte hat.

Ich bin tatsächlich etwa 60% des Weges durch einen ausführlichen Artikel über Autorisierung in AngularJS auf meinem Blog zu schreiben. Ich würde etwa eine Woche einchecken und ich sollte es getan haben - es könnte Ihnen auch mit Route Autorisierung helfen.

UPDATE: Die Blog-Post über Winkel Route Autorisierung und Sicherheit kann here

Grundsätzlich ist der Autorisierungsdienst gefunden würde, um den Benutzer mit Ihrem Backend-Service genehmigen würde es dann Rechte ihrer Anwendung speichern.

Die Direktive würde dann diesen Dienst verwenden, um festzustellen, ob der Benutzer über ausreichende Rechte zum Anzeigen der UI-Komponente verfügt.

Ich habe den folgenden Code nicht getestet, so dass Sie es möglicherweise debuggen müssen.

angular.module('myApp').factory('authService', [ 
    function() { 
     var loggedInUser, 
      login = function (email, password) { 
       //call server and rights are returned 
       //loggedInUser is assigned 
      }, 
      hasSecurityRoles = function (requiredRoles) { 
       var hasRole = false, 
        roleCheckPassed = false, 
        loweredRoles; 
       if (loggedInUser === undefined) { 
        hasRole = false; 
       } else if (loggedInUser !== undefined && requiredRoles === undefined) { 
        hasRole = true; 
       } else if (loggedInUser !== undefined && requiredRoles !== undefined) { 
        if (requiredRoles.length === 0) { 
         hasRole = true; 
        } else if (loggedInUser.permittedActions === undefined) { 
         hasRole = false; 
        } else { 
         loweredRoles = []; 
         angular.forEach(loggedInUser.permittedActions, function (role) { 
          loweredRoles.push(role.name.toLowerCase()); 
         }); 

         // check user has at least one role in given required roles 
         angular.forEach(requiredRoles, function (role) { 
          roleCheckPassed = roleCheckPassed || _.contains(loweredRoles, role.toLowerCase()); 
         }); 

         hasRole = roleCheckPassed; 
        } 
       } 

       return hasRole; 
      }; 

     return { 
      login: login, 
      hasSecurityRoles: hasSecurityRoles 
     }; 
    } 
]); 

    angular.module('myApp').directive('visibleToRoles', [ 
     'authService', 
     function (authService) { 
      return { 
       link: function (scope, element, attrs) { 
        var makeVisible = function() { 
          element.removeClass('hidden'); 
         }, 
         makeHidden = function() { 
          element.addClass('hidden'); 
         }, 
         determineVisibility = function (resetFirst) { 
          if (resetFirst) { 
           makeVisible(); 
          } 

          if (authService.hasSecurityRoles(roles)) { 
           makeVisible(); 
          } else { 
           makeHidden(); 
          } 
         }, 
         roles = attrs.visibleToRoles.split(','); 


        if (roles.length > 0) { 
         determineVisibility(true); 
        } 
       } 
      }; 
     } 
    ]); 

Sie würden dann verwenden, wie diese

<div visible-to-role="admin,usermanager">.....</div> 
+1

Ich mag diesen Ansatz und den Ansatz von @cuttlas sehr gut, aber wenn ich diese Rechte verwende, die in der Richtlinie "Sichtbar zur Rolle" fest codiert sind, sind sie für den Client (in einer Entwicklungsumgebung) immer noch sichtbar. Werkzeuge wie ch Rom). Kann etwas in AngularJS gemacht werden, um diese Direktive und ihre Parameter nach der Auswertung zu löschen? Wie wenn ich Elemente in Chrome auf diesem div überprüfe, möchte ich wirklich "admin, usermanager", hardcoded nicht sehen. (In meinem Beispiel möchte ich nicht, dass die Clients nach den Rechten schnüffeln sollten, die sie benötigen, um bestimmte Aktionen auszuführen oder, um zu sehen, was andere Benutzer auf dieser Seite tun könnten) – Capybara

+0

Und auch ich mag es wirklich nicht, irgendwo in meinem Javascript ist eine Liste der authentifizierten Benutzerrechte. Selbst wenn der Server den Zugriff auf die REST-Endpunkte nicht erlaubt, kann der Benutzer dieses Objekt manipulieren und sich selbst andere Rechte geben. Denke ich zu weit? Oder sollte ich an einfachen Dingen festhalten? :) – Capybara

+1

Ja, Sie sind völlig korrekt, aber selbst wenn Sie das Attribut löschen, nachdem die Direktive verlinkt ist 'el.removeAttr (' visible-to-role ')' Ich könnte einfach Ihren JavaScript-Code anschauen oder besser noch die Direktive ändern . Also solltest du wirklich nichts außerhalb deines Servers denken, wie auch immer irgendwie sicher. Es ist einfacher, 99% Ihrer Benutzerdatenbank zu täuschen - Sicherheit sollte immer auf dem Server erfolgen. – Jon

1

eher eine hartcodierte Liste in Ihren Vorlagen als mit/Seiten können Sie die authentifizierten Benutzer rechte Liste vom Server abrufen und in Ihrem Umfang laden und dann das Gleiche tun, was Sie tun. Wenn Sie den UI-Router verwenden, ist dies möglich, indem Sie die resolve -Eigenschaft verwenden (das bedeutet, dass bestimmte Daten möglicherweise vom Server geladen werden, bevor ein Controller aufgerufen wird).

Auf diese Weise können Sie nur die Rechte für den Benutzer abrufen, der auf die Seite schaut, anstatt alle Rechte im Client fest codieren zu lassen.

+0

Sie für den Kommentar danken. Ich denke, ich habe meine Vorgehensweise nicht sehr gut erklärt, aber ich mache genau das, was du sagst. Die einzigen hartcodierten Dinge sind die Rechte, die in den ng-if-Bedingungen verwendet werden, und ich möchte, dass der Benutzer diese hartcodierten Rechte nicht sieht (Wenn ich beispielsweise die Dev-Tools von Chrome öffne, kann ich sehen all diese hartcodierten Rechte ... – Capybara

+1

Dann können Sie, anstatt die Rechte zu senden, etwas wie "show_feature1", "show_feature2" senden, wobei die Werte von "show_xxx" auf der Serverseite gesetzt sind. Daher sieht der Benutzer a viel abstrakter als der Name des spezifischen Rechten. Ansonsten denke ich, Ihre Vorgehensweise ist in Ordnung. – Sid

12

Mein Ansatz ist im Grunde, was Sie vorschlagen.

Sie könnten eine Fabrik, die das Array von Berechtigungen des Benutzers speichert und eine Funktion zu überprüfen, ob eine Erlaubnis im Array:

.factory('Auth', function() { 

var permissions = []; 

return { 
    allowed : function(permission) { 

     return _.contains(permissions, permission); 
    } 
};}); 

Dann können Sie eine Richtlinie haben, das zeigt/versteckt ein Element mit dem Service:

.directive('allowed', function(Auth){ 

    return { 

     link : function(scope, elem, attr) { 

      if(!Auth.allowed(attr.allowed)){ 
       elem.hide(); 
      } 
     } 
    }; 
}); 

So in Ihren Ansichten müssen Sie nur tun:

<div allowed="permission_name"> </div> 
+0

Vielen Dank für Ihren Kommentar. Ich finde diesen Ansatz sehr einfach, sauber und nützlich. – Capybara

+1

Ich verstehe nicht, warum dies nicht ' Die akzeptierte Lösung – mezod