Skip to content

Controlling access in views

Błażej Krysiak edited this page Apr 6, 2017 · 14 revisions

Before start

Make sure you are familiar with:

Overview

  1. Permission directive
  2. Basic usage
  3. Custom behaviour
  4. Async calls for permissions in initial state
  5. Suppressing warnings for undefined permissions

Permission directive

Permission module exposes directive permission that can show/hide elements of your application based on set of permissions.

Permission directive accepts several attributes:

Attribute Value Description
permission-sref [String] Reference to other state name permissions (ui-router only)
permission-only [String|Array] Single or multiple roles/permissions allowed to access content
permission-except [String|Array] Single or multiple roles/permissions denied to access content
permission-on-authorized [Function] Custom function invoked when authorized
permission-on-unauthorized [Function] Custom function invoked when unauthorized

Basic usage

Directives accepts either single permission that has to be met in order to display it's content:

<div permission 
     permission-only="'canReadInvoice'">
  <span>Congrats! You are logged in.</span>  
</div>

Or set of permissions separated by 'coma':

<div permission 
     permission-except="['USER','ADMIN']">
  <span>You are not 'ADMIN' nor 'USER'.</span>  
</div>

🔥 Important
Do not use permission directive outside ui-view/ng-view, as they are only html elements, that content respond to router state/route changes.

Alternatively, combined together with ui-router, you can reference other state names in order to provide view limitations instead of using permission-only and permission-except properties:

<div permission permission-sref="'app.adminPanel'">
  <span>You must be 'ADMIN' see admin panel!</span>  
</div>

Custom behaviour

By default permission directive is manipulating classes DOM elements by adding or removing ng-hide class using hideElement and showElement behaviour strategies. But permission module exposes additional strategies or even custom function allowing to customize the way elements are being rendered or decorated.

Built in behaviours are stored in PermissionStrategies value containing:

Value Behaviour
enableElement Removes disabled attribute from element
disableElement Adds disabled attribute to element
showElement Removes ng-hide class showing element
hideElement Adds ng-hide class hiding element

To use different strategy pass it as value to permission-on-authorized and permission-on-unauthorized params:

<button 
     type="button" 
     permission 
     permission-only="'canEditInvoice'"
     permission-on-authorized="PermissionStrategies.enableElement"
     permission-on-unauthorized="PermissionStrategies.disableElement">
  Edit Invoice  
</button>

Or you can provide custom function defined inside controller or link function that will be invoked based on authorization results:

angular.controller('InvoiceController', function($scope){
  $scope.onAuthorized = function(element){ 
    element.prepend('<span>Great!</span>');
  };
  
  $scope.onUnauthorized = function(element){ 
    element.prepend('<span>Sad!</span>');
  };
});

And then passed in view to permission attributes:

<button 
     type="button" 
     permission 
     permission-only="'canEditInvoice'"
     permission-on-authorized="onAuthorized"
     permission-on-unauthorized="onUnauthorized">
  Edit Invoice  
</button>

🔥 Important
Notice that functions are being passed as reference (without brackets ()). It is required to allow later invocation. If you pass function with brackets, they simply won't work.

Changing default directive behaviour

In some situations you may want to use different behaviour in all permission directives without the the need to add permission-on-authorized and permission-on-unauthorized everywhere across your code. To do that you should to use $permissionProvider available config phase.

It exposes two methods setDefaultOnAuthorizedMethod and setDefaultOnUnauthorizedMethod that accepts as a string one of available methods defined in PermPermissionStrategies. Feel free to extend it and provide your own methods implementation there.

app
  .config(function ($permissionProvider) {
    $permissionProvider.setDefaultOnAuthorizedMethod('attachElement');
    $permissionProvider.setDefaultOnUnauthorizedMethod('detachElement');
  })
   .run(function (PermPermissionStrategies) {
      PermPermissionStrategies.attachElement = function($element){
        [...]
      };
  
      PermPermissionStrategies.detachElement = function($element){
        [...]
      };
    });

Async calls for permissions in initial states

When using async calls to fetch permissions in initial states make sure that modules (or app) are waiting for permissions to be resolved before running them. To ensure that you should use deferIntercept to create delayed router start.

 var app = ng.module('app', ['ui.router', 'permission', 'permission.ui']);
 
 app
  .config(function ($urlRouterProvider) {
    [...]

    // Prevent router from automatic state resolving
    $urlRouterProvider.deferIntercept();
  })
  .run(function($urlRouter, $http){
    // Example ajax call
    $http
      .get('/permissions')
      .then(function(permissions){
        // Use RoleStore and PermissionStore to define permissions and roles 
        // or even set up whole session
      })
      .then(function(){
        // Once permissions are set-up 
        // kick-off router and start the application rendering
        $urlRouter.sync();
        // Also enable router to listen to url changes
        $urlRouter.listen();
      });
 });

Suppressing warnings for undefined permissions

By default permission library expect you to have defined complete set of roles and permissions defined at the moment of initialization of the app. In same cases your permissions may change dynamically and you can't predict the closed list permissions. Then you wouldn't want your clients to see the warning in console right? To fix that, simply set flag suppressUndefinedPermissionWarning to true on your app configuration stage.

app
  .config(function ($permissionProvider) {
    $permissionProvider.suppressUndefinedPermissionWarning(true);
  })

Next to read: 👉 Installation guide for ui-router
Next to read: 👉 Installation guide for ng-route