Подтвердить что ты не робот

Отображение различного содержимого в пределах одного представления в зависимости от роли пользователя

Предположим, что у нас есть меню в моем приложении angular SPA, теперь я хочу, чтобы основные параметры отображались всем пользователям, например, домой, о нас, возможностях оператора и т.д.

Я также хотел бы иметь несколько других параметров, таких как управление пользователями, сообщения mange и т.д., которые будут отображаться только администратору.

Предположим также, что у нас есть точка доступа API, которая предоставляет мне роль пользователя или, еще лучше, роль пользователя в объекте, полученном из /api/users/me.

Каким будет лучший способ инкапсулировать эти средства управления от просмотра обычными пользователями?

Есть ли какое-то наследование среди представлений? как в Django?, есть ли способ скрыть элементы DOM от неавторизованного пользователя? (да, я знаю, что это клиентская сторона).

Я бы предпочел не использовать разные представления для меню, так как он должен быть родовым компонентом.

Я полагаю, что если ответ на весь мой предыдущий вопрос не будет, остается вопрос: какова наилучшая реализация для этого? пользовательская директива ( "E" + "A" ) скажем:

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

или, возможно, просто используя регулярное ng-show с условием на пользовательском объекте?.

4b9b3361

Ответ 1

Решение находится в этой скрипте:

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 */
            }
        }
    }
});

если вы хотите использовать эту директиву с IE 7 или 8, вам нужно удалить дочерние элементы вручную, в противном случае будет выдана ошибка:

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

Пример возможного использования:

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

Unit test с использованием Karma + Jasmine: Внимание: функция обратного вызова done доступна только для Jasmine 2.0, если вы используете 1.3, вы должны использовать waitsFor вместо этого.

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

Общая директива управления доступом для элементов без использования ng-if (только с V1.2 - в настоящее время нестабильная) или ng-show, которая фактически не удаляет элемент из DOM.

Ответ 2

ng-if определенно так я и сделал! Просто поставьте инструменты модерации во всем представлении, где они принадлежат, и они появятся, если пользователь будет их иметь. ng-show/ng-hide тоже в порядке, если вы используете версию angular до версии 1.1.5.

Живая демонстрация! (нажмите здесь)

ОЧЕНЬ важно, чтобы ваш сервер/сервер/api не выполнял запрос только потому, что ваш js сделал вызов для действия модератора!! Всегда проверяйте сервер на свою авторизацию при каждом вызове.