What's the proper way to hide/show AngularJS, or any other single page application ui components based on authenticated user rights? What's the proper way to hide/show AngularJS, or any other single page application ui components based on authenticated user rights? angularjs angularjs

What's the proper way to hide/show AngularJS, or any other single page application ui components based on authenticated user rights?


My approach is basically what you suggest.

You could have a factory which stores the array of permissions of the user and has a function to check if a permission is in the array:

.factory('Auth', function() {var permissions = [];return {    allowed : function(permission) {        return _.contains(permissions, permission);    }};});

Then you can have a directive, that shows/hides an element using the service:

.directive('allowed', function(Auth){    return {        link : function(scope, elem, attr) {            if(!Auth.allowed(attr.allowed)){                elem.hide();            }        }    };});

So in your views you only have to do:

<div allowed="permission_name"> </div>


Security on the client i.e. in a browser is next to useless. However, it should be present to stop the average user from seeing something they shouldn't however the server should be the ultimate place security is carried out.

I'd create a quick directive to do the showing / hiding or UI components and have a authentication service to do the actual logic to determine if the user has the correct rights.

I'm actual about 60% of the way through writing an in depth article about authorisation in AngularJS on my blog. I'd check back in about a week and I should have it done - it might help you with route authorisation as well.

UPDATE: The blog post about angular route authorization and security can be found here

Basically the authorisation service would authorise the user with your backend service it would then store their application rights.

The directive would then use this service to determine if the user has enough rights to see the UI component.

I haven't tested the below code so you might need to debug it.

    angular.module('myApp').factory('authService', [    function () {        var loggedInUser,            login = function (email, password) {                //call server and rights are returned                //loggedInUser is assigned            },            hasSecurityRoles = function (requiredRoles) {                var hasRole = false,                    roleCheckPassed = false,                    loweredRoles;                if (loggedInUser === undefined) {                    hasRole = false;                } else if (loggedInUser !== undefined && requiredRoles === undefined) {                    hasRole = true;                } else if (loggedInUser !== undefined && requiredRoles !== undefined) {                    if (requiredRoles.length === 0) {                        hasRole = true;                    } else if (loggedInUser.permittedActions === undefined) {                        hasRole = false;                    } else {                        loweredRoles = [];                        angular.forEach(loggedInUser.permittedActions, function (role) {                            loweredRoles.push(role.name.toLowerCase());                        });                        // check user has at least one role in given required roles                        angular.forEach(requiredRoles, function (role) {                            roleCheckPassed = roleCheckPassed || _.contains(loweredRoles, role.toLowerCase());                        });                        hasRole = roleCheckPassed;                    }                }                return hasRole;            };        return {            login: login,            hasSecurityRoles: hasSecurityRoles        };    }]);    angular.module('myApp').directive('visibleToRoles', [        'authService',        function (authService) {            return {                link: function (scope, element, attrs) {                    var makeVisible = function () {                            element.removeClass('hidden');                        },                        makeHidden = function () {                            element.addClass('hidden');                        },                        determineVisibility = function (resetFirst) {                            if (resetFirst) {                                makeVisible();                            }                            if (authService.hasSecurityRoles(roles)) {                                makeVisible();                            } else {                                makeHidden();                            }                        },                        roles = attrs.visibleToRoles.split(',');                    if (roles.length > 0) {                        determineVisibility(true);                    }                }            };        }    ]);

You would then use it like this

<div visible-to-role="admin,usermanager">.....</div>


Rather than having a hard-coded list in your templates/pages you could retrieve the authenticated user right list from the server and load it in your scope and then do the same thing that you are doing.If you are using ui-router this is possible by using the resolve property (that is pre-loading certain data possibly from the server before a controller is called).

This way you can only retrieve the rights for the user that is looking at the page rather than have all rights hard-coded in the client.