Search code examples
angularjslaraveldesign-patternslogicfetching-strategy

Handling many different types of roles and data retrieval


Just to note, I'm using Laravel on the backend. Let's say you had 10 different user levels in an task management system. All these user levels have different access to the tasks themselves, as well as the actual attributes for each task. For example, a super admin might be able to see all the tasks, and a manager too. But the manager only sees a certain subset of attributes for those tasks. On the flip side, a regular would only see their own tasks, and a different subset of the attributes too.

What kind of design pattern or method would you use to handle something like this? It's different for each of the user levels, and I'm trying to avoid having to add switch statements everywhere. For simple things, it's totally fine. But when it's everywhere, it seems like a code smell.

That's basically what I'm trying to find a good solution for. There's something else where I'm returning an array to the view, but the array would be populated with different sets of information depending on the user level. I'm trying to limit the sent data, even if it doesn't show up, because I'm using Angular on the front. So it's pretty simple to check the response for that data.


Solution

  • I would look into using something like this project: https://github.com/Narzerus/angular-permission

    According to the documentation:

    Permission helps you gain control of your routes, by using simple concepts for you to decide who can access them. I've seen plenty of big fat tutorials on access control implementations, and they can be quite overwhelming. So I bring you a simple, powerful, straightforward solution.

    Here is a simple example on how you could implement it in Angular:

    Defining permissions:

    angular.module('barModule', ['permission', 'user'])
    .run(function (PermissionStore, User, $q) {
      PermissionStore
        // Define user permission calling back-end
        .definePermission('user', function (stateParams) {
          // This time we will return a promise
          // If the promise *resolves* then the user has the permission, if it *rejects* (you guessed it)
    
          // Let's assume this returns a promise that resolves or rejects if session is active
          return User.checkSession();
        })
    
      PermissionStore
        // A different example for admin
        .definePermission('admin', function (stateParams) {
          var deferred = $q.defer();
    
          User.getAccessLevel()
            .then(function (data) {
              if (data.accessLevel === 'admin') {
                deferred.resolve();
              } else {
                deferred.reject();
              }
            }
            .catch(function () {
              // Error with request
              deferred.reject();
            });
    
          return deferred.promise;
        });
    });
    

    Defining Roles:

    angular
    .module('fooModule', ['permission', 'user'])
    .run(function (RoleStore, User) {
      RoleStore
        // Permission array validated role
        // Library will internally validate if 'user' and 'editor' permissions are valid when checking if role is valid   
        .defineRole('admin', ['user', 'editor']);  
    
      RoleStore    
        // Server side validated role
        .defineRole('accountant', [], function (stateParams) {
          // Let's assume that we are making a request to server here and return response as promise        
          return User.hasRole('accountant');
        });
    });
    

    Usage in the routes:

    $stateProvider
    .state('dashboard', {
      url: '...',
      data: {
        permissions: {
          except: ['anonymous'],
          redirectTo: 'login'
        }
      }
    });
    

    Usage in views:

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