webentwicklung-frage-antwort-db.com.de

Anzeige verschiedener Inhalte in einer einzelnen Ansicht, basierend auf der Rolle des Benutzers

Nehmen wir an, wir haben ein Menü in meiner eckigen SPA-Anwendung. Jetzt möchte ich, dass die grundlegenden Optionen allen Benutzern angezeigt werden, z. B. zu Hause, Informationen zu uns, Möglichkeiten für Spediteure usw.

Ich möchte auch mehrere andere Optionen haben, z. B. Benutzer verwalten, Beiträge verwalten usw., die nur einem Administrator angezeigt werden.

Nehmen wir auch an, dass wir über einen API-Zugangspunkt verfügen, der mir die Benutzerrolle oder, noch besser, die Benutzerrolle, innerhalb des Objekts gibt, das von/api/users/me abgerufen wird.

Was wäre der beste Weg, um diese Management-Tools von regulären Benutzern einzubinden?.

Gibt es eine Art Vererbung zwischen Ansichten? Wie in Django? Gibt es eine Möglichkeit, die DOM-Elemente vor dem nicht autorisierten Benutzer zu verbergen? (Ja, ich weiß, dass es clientseitig ist).

Ich würde es wirklich vorziehen, keine unterschiedlichen Ansichten für das Menü zu verwenden, da es sich um eine generische Komponente handelt.

Ich denke, wenn die Antwort auf alle meine vorherigen Fragen nein ist, dann bleibt die Frage: Was ist die beste Implementierung dafür? eine benutzerdefinierte Direktive ("E" + "A")

<limitedAccss admin>Edit page</limitedAccess>
 <limitedAccss user>view page</limitedAccess>

oder vielleicht nur die normale ng-show mit einer Bedingung für das Benutzerobjekt?.

29
Oleg Belousov

Die Lösung liegt in dieser Geige:

http://jsfiddle.net/BmQuY/3/

var app = angular.module('myApp', []);

app.service('authService', function(){

  var user = {};
  user.role = 'guest';
  return{
    getUser: function(){
      return user;
    },
    generateRoleData: function(){
      /* this is resolved before the 
         router loads the view and model.
         It needs to return a promise. */
      /* ... */
    }
  }
});

app.directive('restrict', function(authService){
    return{
        restrict: 'A',
        priority: 100000,
        scope: false,
        compile:  function(element, attr, linker){
            var accessDenied = true;
            var user = authService.getUser();

            var attributes = attr.access.split(" ");
            for(var i in attributes){
                if(user.role == attributes[i]){
                    accessDenied = false;
                }
            }


            if(accessDenied){
                element.children().remove();
                element.remove();           
            }


            return function linkFn() {
                /* Optional */
            }
        }
    }
});

wenn Sie diese Direktive mit IE 7 oder 8 verwenden möchten, müssen Sie die untergeordneten Elemente des Elements manuell entfernen. Andernfalls wird ein Fehler ausgegeben:

  angular.forEach(element.children(), function(Elm){
    try{
      Elm.remove();
    }
    catch(ignore){}
  });

Beispiel für eine mögliche Verwendung:

<div data-restrict access='superuser admin moderator'><a href='#'>Administrative options</a></div>

Unit-Test mit Karma + Jasmine: Achtung: Die done-Callback-Funktion ist nur für Jasmine 2.0 verfügbar. Wenn Sie 1.3 verwenden, sollten Sie stattdessen waitsFor verwenden.

  describe('restrict-remove', function(){
    var scope, compile, html, elem, authService, timeout;
    html = '<span data-restrict data-access="admin recruiter scouter"></span>';
    beforeEach(function(){
      module('myApp.directives');
      module('myApp.services');
      inject(function($compile, $rootScope, $injector){
        authService = $injector.get('authService');
        authService.setRole('guest');
        scope = $rootScope.$new();
        // compile = $compile;
        timeout = $injector.get('$timeout');
        elem = $compile(html)(scope);
        elem.scope().$apply();
      });
    });
    it('should allow basic role-based content discretion', function(done){
        timeout(function(){
          expect(elem).toBeUndefined(); 
          done(); //might need a longer timeout;
        }, 0);
    });
  });
  describe('restrict-keep', function(){
    var scope, compile, html, elem, authService, timeout;
    html = '<span data-restrict data-access="admin recruiter">';
    beforeEach(function(){
      module('myApp.directives');
      module('myApp.services');
      inject(function($compile, $rootScope, $injector){
        authService = $injector.get('authService');
        timeout = $injector.get('$timeout');
        authService.setRole('admin');
        scope = $rootScope.$new();
        elem = $compile(html)(scope);
        elem.scope().$apply();
      });
    });

    it('should allow users with sufficient priviledsges to view role-restricted content', function(done){
      timeout(function(){
        expect(elem).toBeDefined();
        expect(elem.length).toEqual(1);
        done(); //might need a longer timeout;
      }, 0)
    })
  });

Eine generische Zugriffssteuerungs-Direktive für Elemente, ohne ng-if (nur seit V1.2 - derzeit nicht stabil) oder ng-show zu verwenden, wodurch das Element nicht wirklich aus dem DOM entfernt wird.

38
Oleg Belousov

ng-ifist definitiv so wie ich es machen würde! Setzen Sie die Moderationswerkzeuge einfach in die Ansicht, wo sie hingehören, und sie werden angezeigt, wenn der Benutzer sie haben sollte. ng-show/ng-hide ist auch in Ordnung, wenn Sie eine Winkelversion vor 1.1.5 verwenden.

Live Demo! (Klick hier)

Es ist sehr wichtig, dass Sie sicherstellen, dass Ihr Backend/Server/API keine Anforderung erfüllt, nur weil Ihre js eine Moderatoraktion aufgerufen haben !! Lassen Sie den Server immer bei jedem Aufruf die Autorisierung überprüfen.

3
m59

ng-if oder ng-hide sind dafür in Ordnung, 

die HTML-Datei ist nur eine Ansicht und sollte nicht für den Umgang mit Sicherheit, Ihrer Sicherheit, verantwortlich sein

Wenn ein Berechtigungsobjekt mit dem Benutzer verknüpft ist, kann dies nützlich sein. Wenn ich Benutzerdaten abrufe, erhalte ich eine Erlaubnis json dann auf dem Winkel 

<div ng-if="user.permissions.restrictedArea">Very restricted area</div>

Und der Benutzer Json sieht so aus:

{name:"some one", permissions:{restrictedArea:false,sandbox:true}} //and so on...
0
Jonathan