Skip to content

Managing permissions

AlexKhymenko edited this page Jun 10, 2019 · 3 revisions

Overview

  1. Introduction
  2. Defining permissions
  3. Individual permissions
  4. To load permissions before application start up
  5. Multiple permissions
  6. Removing permissions
  7. Retrieving permissions

Introduction

Let's start with little explanation what permission is. Permission is the most atomic ability that a user can have in your application. So you can think about permission as a smallest action that user can do inside your site.

But can user or anonymous be a permission? Technically yes, but from business point of view you should treat them as Roles that are more complex objects that can store more complex logic.

💡 Note
It's a good convention to start permission with a verb and combine them with resource or object, so permissions like readDocuments or listSongs are meaningful and easy to understand for other programmes. Notice that they are named lowerCamelCase for easy differentiation form roles.

💀 Warning
This library is intended for simplify the client side development workflow in a role based web application. DO NOT RELY ONLY ON THIS CHECKS FOR YOU APPLICATION SECURITY! Client side checks can be easily bypassed, so always implement the checks on the backend!

Defining permissions

So, how do you tell Permission what does 'readDocuments' or 'listSongs' mean and how to know if the current user belongs to those definitions?

Well, Permission allows you to set different 'permissions' definitions along with the logic that determines if the current session belongs to them. To do that library exposes special container NgxPermissionsService that allows you to manipulate them freely.

Individual permissions

To add permissions individually NgxPermissionsService exposes method addPermission that generic usage is shown below or add as array:

[...]
 ngOnInit() {
    this.permissionsService.addPermission('changeSomething')
    this.permissionsService.addPermission(['changeSomething', 'anotherAlso'])
    this.permissionsService.addPermission('changeSomething', () => {
        return true;
    })
     
    this.permissionsService.addPermission('anotherPermissions', (permissionName, permissionsObject) => {
        return !!permissionsObject[permissionName];
    });
    this.permissionsService.addPermission(['anotherPermissions', 'AnotherOne'], (permissionName, permissionsObject) => {
        return !!permissionsObject[permissionName];
    });
     
    //Will add validation function to every permission
     this.permissionsService.addPermission(['anotherPermissions', 'AnotherOne'], (permissionName, permissionsObject) => {
         return !!permissionsObject[permissionName];
     });
     
     this.permissionsService.addPermission('permissions', (permissionName, permissionsObject) => {
       return this.checkSession().toPromise();
     });
 }

To load permissions before application start up

APP_INITIALIZER is defined in angular/core. You include it in your app.module.ts like this.

APP_INITIALIZER is an OpaqueToken that references the ApplicationInitStatus service. ApplicationInitStatus is a multi provider. It supports multiple dependencies and you can use it in your providers list multiple times. It is used like this.

import { APP_INITIALIZER } from '@angular/core';

@NgModule({
  providers: [
    DictionaryService,
    {
      provide: APP_INITIALIZER,
      useFactory: (ds: DictionaryService, ps: NgxPermissionsService ) => function() {return ds.load().then((data) => {return ps.loadPermissions(data)})},
      deps: [LoadService, NgxPermissionsService],
      multi: true
    }]
})
export class AppModule { }

Validation function are injected with any angular services. There are 2 local injectables available that can be used to implement more complex validation logic.

Injectable Local Description
permissionName String representing name of checked permission
permissionsObject Object of store permissions storing permissions properties

It also have to return one of values to properly represent results:

Validation result Returned value
Valid [true|Promise.resolve() but it should not resolve false]
Invalid [false|Promise.reject() or Promise.resolve(false)]

Multiple permissions

To define multiple permissions method loadPermissions can be used. The difference between loadPermissions and addPermission. LoadPermission will remove older permissions and pass only new;

Often meet example of usage is set of permissions (e.g. received from server after user login) that you will iterate over to check if permission is valid.

const permissions = ['listMeeting', 'seeMeeting', 'editMeeting', 'deleteMeeting']
NgxPermissionsService.loadPermissions(permissions) 
NgxPermissionsService.loadPermissions(permissions, (permissionName, permissionStore) => {
    return !!permissionStore[permissionName];
}) 

💡 Note : This method will remove older permissions and pass only new;

Removing permissions

You can easily remove ALL permissions form the NgxPermissionsService (e.g. after user logged out or switched profile) by calling:

NgxPermissionsService.flushPermissions();           - removes ALL permissions

Alternatively you can use removePermission to delete defined permissions manually:

NgxPermissionsService.removePermission('user');

Retrieving permissions

And to get all user permissions use method getPermissions or use Observable permissions$:

var permissions = NgxPermissionsService.getPermissions();

NgxPermissionsService.permissions$.subscribe((permissions) => {
    console.log(permissions)
})