Spurtcommerce launches its Multi-Vendor eCommerce Solution, built on the latest NodeJS and Angular technologies. Multi Vendor

Finest approach for Role based Authentication in Admin

Know how the Spurtcommerce team has followed the exceptional strategy for implementing the Access Control for granting and denying permissions.

Access Control List establishes rules that grant or deny access to certain Roles and Users performing those Roles.

 

eCommerce Applications does require to have their appearance and behaviour based on the user’s role or permission. Users should only be presented with certain permissions or access based on their role or a set of actions that they can undertake within the Application. This is not a replacement for securing the data at the API level, however, it improves the usability on the client. This article provides sample code that Spurtcommerce has used to implement this feature in our Angular eCommerce Application.

 

How have we implemented ACL in Spurtcommerce

  1. Super Admin will have access to the entire and whole Admin Control Panel. They will have default permissions to access every module within the eCommerce Application.
  2. This Super Admin can create additional Admin Users. Those additional Admin Users need not be granted permission or access to the entire Admin Control Panel. For example, an Accountant will need access to the payment section, while a Catalog Manager will need access to the Categories and Products Section.
  3. So, for each role, the Admin can configure permissions. However, this need not be fixed for a particular User. A User can play multiple roles and have access accordingly. Say for example, if a User plays the role of an Accountant as well as a Catalog Manager, then the permissions can be over written, so that the User has access to all the modules of both Accountant as well as Catalog Manager.
  4. So, the permissions can be defined at Role level and then at User level also.

For this purpose, we have written a Service.

Create an permission service

Centralize the checking of permissions into an Angular service.

import { Injectable } from '@angular/core';
import { Promise } from 'es6-promise';
import { Api } from '../../../../../../core/admin/providers/api/api';
import { environment } from '../../../../../../environments/environment';

@Injectable()
export class PermissionServices extends Api {
  private URL = environment.baseUrl;
  permissions: any = []; // Store the actions for which this user has permission
  currentUser: any;

  hasPermission(authGroup: string): Promise | boolean {
    console.log('Inside Permission', authGroup);
    this.permissions = localStorage.getItem('permissions')
      ? JSON.parse(localStorage.getItem('permissions'))
      : {};
    const role: number = localStorage.getItem('adminUser')
      ? JSON.parse(localStorage.getItem('adminUser'))
      : {};
    const permissionKeys = this.permissions
      ? Object.keys(this.permissions)
      : [];
    console.log(role);
    if (role['usergroup'].groupId === 1) {
      return true;
    } else if (
      permissionKeys.length > 0 &&
      permissionKeys.indexOf(authGroup) > -1 &&
      this.permissions[authGroup]
    ) {
      console.log('working');
      return true;
    }
  }

  // This method is called once and a list of permissions is stored in the permissions property
  initializePermissions() {
    return new Promise((resolve, reject) => {
      // Call API to retrieve the list of actions this user is permitted to perform.
      // In this case, the method returns a Promise, but it could have been implemented as an Observable
      this.http
        .get(this.URL + '/get-permission')
        .subscribe(
          response => {
            console.log(response);
            const permissions = response.data;
            const permissionKeys = response.data
              ? Object.keys(response.data).filter(function (el) {
                return response.data[el] === true;
              })
              : [];
            permissions['sales'] = false;
            permissions['sales-payments'] = false;
            permissions['catalog'] = false;
            permissions['catalog-product'] = false;
            permissions['catalog-brand'] = false;
            permissions['catalog-category'] = false;
            permissions['catalog-product-option'] = false;
            permissions['catalog-rating-review'] = false;
            permissions['catalog-coupon'] = false;
            permissions['customers'] = false;
            permissions['customers-customer'] = false;
            permissions['customer-groups'] = false;
            permissions['cms'] = false;
            permissions['cms-pages'] = false;
            permissions['cms-banners'] = false;
            permissions['cms-blogs'] = false;
            permissions['services'] = false;
            permissions['services-lists'] = false;
            permissions['services-category'] = false;
            permissions['services-enquiry'] = false;
            permissions['services-lead'] = false;
            permissions['marketplace'] = false;
            permissions['marketplace-vendor'] = false;
            permissions['vendor-list'] = false;
            permissions['vendor-product'] = false;
            permissions['vendor-settings'] = false;
            permissions['marketplace-sales'] = false;
            permissions['marketplace-payments'] = false;
            permissions['settings'] = false;
            permissions['settings-role'] = false;
            permissions['settings-user'] = false;
            permissions['settings-general-setting'] = false;
            permissions['settings-site'] = false;
            permissions['settings-local'] = false;
            permissions['settings-personalize'] = false;


            console.log(permissionKeys);
            // payment permission
            if ((permissionKeys.indexOf('list-order') > -1 && permissions['list-order'])) {
              permissions['sales'] = true;
            }
            if (
              (permissionKeys.indexOf('list-sales-payments') > -1 &&
                permissions['list-sales-payments'])
            ) {
              permissions['sales-payments'] = true;
              permissions['sales'] = true;
            }
            // product permission
            if (
              (permissionKeys.indexOf('create-product') > -1 &&
                permissions['create-product']) ||
              (permissionKeys.indexOf('list-product') > -1 &&
                permissions['list-product'])
            ) {
              permissions['catalog-product'] = true;
              permissions['catalog'] = true;
            }
            // create permission
            if (
              (permissionKeys.indexOf('create-category') > -1 &&
                permissions['create-category']) ||
              (permissionKeys.indexOf('list-category') > -1 &&
                permissions['list-category'])
            ) {
              permissions['catalog-category'] = true;
              permissions['catalog'] = true;
            }
            // create product option permission
            if (
              (permissionKeys.indexOf('create-product-option') > -1 &&
                permissions['create-product-option']) ||
              (permissionKeys.indexOf('list-product-option') > -1 &&
                permissions['list-category'])
            ) {
              permissions['catalog-product-option'] = true;
              permissions['catalog'] = true;
            }
            // list rating review permission
            if (
              permissionKeys.indexOf('list-rating-review') > -1 &&
              permissions['list-rating-review']
            ) {
              permissions['catalog-rating-review'] = true;
              permissions['catalog'] = true;
            }
            // create coupon permission
            if (
              permissionKeys.indexOf('create-coupon') > -1 &&
              permissions['create-coupon'] ||
              (permissionKeys.indexOf('list-coupon') > -1 &&
                permissions['list-coupon'])
            ) {
              permissions['catalog-coupon'] = true;
              permissions['catalog'] = true;
            }
            // create brand permission
            if (
              permissionKeys.indexOf('create-brands') > -1 &&
              permissions['create-brands'] ||
              (permissionKeys.indexOf('list-brands') > -1 &&
                permissions['list-brands'])
            ) {
              permissions['catalog-brand'] = true;
              permissions['catalog'] = true;
            }
            // customer list permission
            if (
              (permissionKeys.indexOf('create-customer') > -1 &&
                permissions['create-customer']) ||
              (permissionKeys.indexOf('list-customer') > -1 &&
                permissions['list-customer'])
            ) {
              permissions['customers-customer'] = true;
              permissions['customers'] = true;
            }
            // customer customer group permission
            if (
              (permissionKeys.indexOf('create-customer-group') > -1 &&
                permissions['create-customer-group']) ||
              (permissionKeys.indexOf('list-customer-group') > -1 &&
                permissions['list-customer-group'])
            ) {
              permissions['customer-groups'] = true;
              permissions['customers'] = true;
            }
            // pages permission
            if (
              (permissionKeys.indexOf('create-pages') > -1 &&
                permissions['create-pages']) ||
              (permissionKeys.indexOf('list-pages') > -1 &&
                permissions['list-pages'])
            ) {
              permissions['cms-pages'] = true;
              permissions['cms'] = true;
            }
            // banner permission
            if (
              (permissionKeys.indexOf('create-banners') > -1 &&
                permissions['create-banners']) ||
              (permissionKeys.indexOf('list-banners') > -1 &&
                permissions['list-banners'])
            ) {
              permissions['cms-banners'] = true;
              permissions['cms'] = true;
            }
            // blogs permission
            if (
              (permissionKeys.indexOf('create-blogs') > -1 &&
                permissions['create-blogs']) ||
              (permissionKeys.indexOf('list-blogs') > -1 &&
                permissions['list-blogs'])
            ) {
              permissions['cms-blogs'] = true;
              permissions['cms'] = true;
            }
            // service list permission
            if (
              (permissionKeys.indexOf('create-services') > -1 &&
                permissions['create-services']) ||
              (permissionKeys.indexOf('list-services') > -1 &&
                permissions['list-services'])
            ) {
              permissions['services-lists'] = true;
              permissions['services'] = true;
            }
            // service category permission
            if (
              (permissionKeys.indexOf('create-service-category') > -1 &&
                permissions['create-service-category']) ||
              (permissionKeys.indexOf('list-service-category') > -1 &&
                permissions['list-service-category'])
            ) {
              permissions['services-category'] = true;
              permissions['services'] = true;
            }
            // service enquiry permission
            if (
              permissionKeys.indexOf('list-service-enquiry') > -1 &&
              permissions['list-service-enquiry']
            ) {
              permissions['service-enquiry'] = true;
              permissions['services'] = true;
            }
            // service lead permission
            if (
              permissionKeys.indexOf('list-leads') > -1 &&
              permissions['list-leads']
            ) {
              permissions['services-lead'] = true;
              permissions['services'] = true;
            }
            if (
              (permissionKeys.indexOf('create-vendor') > -1 &&
                permissions['create-vendor']) ||
              (permissionKeys.indexOf('list-vendor') > -1 &&
                permissions['list-vendor'])
            ) {
              permissions['marketplace'] = true;
              permissions['marketplace-vendor'] = true;
              permissions['vendor-list'] = true;
            }
            if (
              (permissionKeys.indexOf('create-market-place-product') > -1 &&
                permissions['create-market-place-product']) ||
              (permissionKeys.indexOf('list-market-place-product') > -1 &&
                permissions['list-market-place-product'])
            ) {
              permissions['marketplace'] = true;
              permissions['marketplace-vendor'] = true;
              permissions['vendor-product'] = true;
            }
            if (
              (permissionKeys.indexOf('assign-category') > -1 &&
                permissions['assign-category']) ||
              (permissionKeys.indexOf('set-vendor-commission') > -1 &&
                permissions['set-vendor-commission'])
            ) {
              permissions['vendor-settings'] = true;
              permissions['marketplace-vendor'] = true;
              permissions['marketplace'] = true;
            }
            if (
              permissionKeys.indexOf('list-sales') > -1 &&
              permissions['list-sales']
            ) {
              permissions['marketplace'] = true;
              permissions['marketplace-sales'] = true;
            }
            if (
              (permissionKeys.indexOf('list-payment') > -1 &&
                permissions['list-payment']) ||
              (permissionKeys.indexOf('export-all-payment') > -1 &&
                permissions['export-all-payment'])
            ) {
              permissions['marketplace'] = true;
              permissions['marketplace-payments'] = true;
            }

            // setting role
            if (
              (permissionKeys.indexOf('list-role') > -1 &&
                permissions['list-role'])
            ) {
              permissions['settings'] = true;
              permissions['settings-role'] = true;
            }


            // setting user
            if (
              (permissionKeys.indexOf('list-user') > -1 &&
                permissions['list-user'])
            ) {
              permissions['settings'] = true;
              permissions['settings-user'] = true;
            }


            if (
              (permissionKeys.indexOf('list-country') > -1 &&
                permissions['list-country'])
            ) {
              permissions['settings-local'] = true;
              permissions['settings'] = true;
            }
            if (
              (permissionKeys.indexOf('list-language') > -1 &&
                permissions['list-language'])
            ) {
              permissions['settings'] = true;
              permissions['settings-local'] = true;
            }
            if (
              (permissionKeys.indexOf('list-currency') > -1 &&
                permissions['list-currency'])
            ) {
              permissions['settings'] = true;
              permissions['settings-local'] = true;
            }
            if (
              (permissionKeys.indexOf('list-tax') > -1 &&
                permissions['list-tax'])
            ) {
              permissions['settings'] = true;
              permissions['settings-local'] = true;
            }
            if (
              (permissionKeys.indexOf('list-order-status') > -1 &&
                permissions['list-order-status'])
            ) {
              permissions['settings'] = true;
              permissions['settings-local'] = true;
            }
            if (
              (permissionKeys.indexOf('list-stock-status') > -1 &&
                permissions['list-stock-status'])
            ) {
              permissions['settings'] = true;
              permissions['settings-local'] = true;
            }
            if (
              (permissionKeys.indexOf('list-email-template') > -1 &&
                permissions['list-email-template'])
            ) {
              permissions['settings'] = true;
              permissions['settings-local'] = true;
            }


          // general settins

          if (
            (permissionKeys.indexOf('edit-general-settings') > -1 &&
            permissions['edit-general-settings'])
          ) {
            permissions['settings'] = true;
            permissions['settings-general-setting'] = true;
          }

          // pesonalize

           if (
            (permissionKeys.indexOf('edit-personalize-order') > -1 &&
            permissions['edit-personalize-order'])
          ) {
            permissions['settings'] = true;
            permissions['settings-personalize'] = true;
          }

          if (
            (permissionKeys.indexOf('edit-personalize-product') > -1 &&
            permissions['edit-personalize-product'])
          ) {
            permissions['settings'] = true;
            permissions['settings-personalize'] = true;
          }

          // site settings

          if (
            (permissionKeys.indexOf('edit-seo-url') > -1 &&
            permissions['edit-seo-url'])
          ) {
            permissions['settings'] = true;
            permissions['settings-site'] = true;
          }

          if (
            (permissionKeys.indexOf('edit-social-url') > -1 &&
            permissions['edit-social-url'])
          ) {
            permissions['settings'] = true;
            permissions['settings-site'] = true;
          }

          // localizations

          if (
            (permissionKeys.indexOf('list-zone') > -1 &&
            permissions['list-zone'])
          ) {
            permissions['settings'] = true;
            permissions['settings-local'] = true;
          }

            this.permissions = permissions;
            localStorage.setItem(
              'permissions',
              JSON.stringify(this.permissions)
            );
            resolve(true);
          },
          err => {
            reject(err);
          }
        );
    });
  }
}

We have written the Directives

Create attribute directives to hide and disable elements

disable-if-unauthorized.directive.ts

import {Directive, ElementRef, OnInit, Input} from '@angular/core';
import { PermissionServices } from '../../../../../../theme/default/admin/shared/components/services/permission.services';

@Directive({
    selector: '[appDisableIfUnauthorized]'
})
export class MyDisableIfUnauthorizedDirective implements OnInit {
    @Input('appDisableIfUnauthorized') permission: string; // Required permission passed in
    constructor(private el: ElementRef, private permissionServices: PermissionServices) {
    }

    ngOnInit() {
        if (!this.permissionServices.hasPermission(this.permission)) {
            this.el.nativeElement.disabled = true;
        }
    }
}

hide-if-unauthorized.directive.ts

import {Directive, ElementRef, OnInit, Input} from '@angular/core';
import { PermissionServices } from '../../../../../../theme/default/admin/shared/components/services/permission.services';

@Directive({
    selector: '[appHideIfUnauthorized]'
})
export class MyHideIfUnauthorizedDirective implements OnInit {
    @Input('appHideIfUnauthorized') permission: string; // Required permission passed in
    constructor(private el: ElementRef, private permissionServices: PermissionServices) {
    }

    ngOnInit() {
        console.log(this.permissionServices.hasPermission(this.permission), this.permission, 'permission status');
        if (!this.permissionServices.hasPermission(this.permission)) {
            this.el.nativeElement.style.display = 'none';
        }
    }
}