10

I am trying to write directive that will evaluate user permissions.

In case user is not permitted to see given content

  1. the content will not be displayed (done, working fine)

  2. requests from controllers inside permission directive will not get fired.

Example:

Controller:

function MyController ($scope){
     // performing imediately server request, witch is allowed only for admin
     // therefore i will get error when non admin user access this page
}

Permission directive:

return {
        priority: 1000,
        restrict: 'E',
        link: (scope, element, attrs) => {
            var permission = attrs.permission;

            if (/*evaluating permission*/) { 
                // user has permission, no work for me
                return;
            }

            element.remove();
        }
    };

All together:

<permission permission="isAdmin">
    <div ng-controller="MyController">
    </div>
</permission>

This version is removing elements from DOM, but request in MyController still gets executed. Off course, I can make check for permissions in MyController, but I don't want to.

Thank for help.

klesta
  • 161
  • 1
  • 9
  • Please show us how you are doing your $http request. – Ray Garner Mar 12 '13 at 21:10
  • or make a jsfiddle. I think I know what your problem is but want to see more of your code to be sure. – Ray Garner Mar 12 '13 at 21:10
  • 2 Ray: it's just a standard $http.post `$http.post(address, data).success(succCall).error( errCall);` [jsfiddle](http://jsfiddle.net/sdYgp/2/) I don't see how this is relevant. I have found out, that removing element in compile works, but I am not sure if it is good solution. – klesta Mar 14 '13 at 07:12

3 Answers3

2

Your issue is that the controller will always be called before the link function executes. See this fiddle.

function MyCtrl($scope) {
    console.log('in controller');
}

myApp.directive('permission', function() {
    return {
        restrict: 'E',
        link: function(scope, element, attrs) {
            console.log('in link');

Log shows:

in controller
in link
Mark Rajcok
  • 362,217
  • 114
  • 495
  • 492
  • based on this answer I tried another approach and put removal of element into **compile** function. According to log, it is executed BEFORE controller, so it is right place. Anyway the request was still fired. So I tried just as a blind shot remove element children (I know, it does not make sense, removal of element should be sufficient and should remove children also). But it worked! `compile: function(element) { var children = element.children(); children.remove(); element.remove(); }` - what do you say on this? It is working, but I am not sure how much OK it is (e.g. future version Ang.) – klesta Mar 12 '13 at 15:08
  • @klesta, element.remove() seems to work for me in the compile function: [fiddle](http://jsfiddle.net/mrajcok/MFHet/2/). If I understand your general approach, it has bigger problems because someone could modify your JavaScript and get access to things they shouldn't have access to. – Mark Rajcok Mar 12 '13 at 15:22
  • well they can modify it and see for example admin section, but they would not be allowed to do anything since server won't let them – klesta Mar 12 '13 at 16:03
  • (server wont let them even fetch items they don't have rights to) – klesta Mar 12 '13 at 16:15
  • @klesta, okay, good. I was under the (wrong) impression that you were going to hide content that only an administrator should see. – Mark Rajcok Mar 12 '13 at 16:27
  • Yes me too. I was under the same impression. – Ray Garner Mar 12 '13 at 21:00
  • Ok guys, as I understand it, calling `remove()` on child elements works. Do you know why? Why only removing the element itself doesn't help? – stej Mar 13 '13 at 06:56
  • Mark Rajcok could you please explain is this the best solution for check area shown under role? – Gayan Nov 04 '14 at 09:58
1

I tried another approach and put removal of element into compile function. According to log, it is executed BEFORE controller, so it is right place. Anyway the request was still fired. So I tried just as a blind shot remove element children (I know, it does not make sense, removal of element should be sufficient and should remove children also).

But it worked!

compile: function(element) { var children = element.children(); children.remove(); element.remove(); }

It is working, but I am not sure how much OK it is (e.g. future version Ang.)

klesta
  • 161
  • 1
  • 9
  • I am facing the same problem, can you please post the entire code?. Have you modified the link function some how, or have you just added those lines beneath? – Oleg Belousov Aug 06 '13 at 11:17
-1

If I were you I would make a call to the server and check if they are authorised for access.

Doing this with a directive does not really make sense.

Directives are generally for manipulating dom and this is authorisation confirmation should generally be handled in the controller and then have the result of that trigger an event.

Then have your directive be listening for that event and manipulate the dom if they got access from the server.

Otherwise anyone could easily just inject whatever they wanted and see your admin panel.

If your not sure what I mean let me know I can expand the answer if you need me to.

Ray Garner
  • 932
  • 1
  • 10
  • 18
  • well server side is protected... when unauthorized user makes request, there are answers like 'no rights'. Your way look like too much effort for relatively simple task :). Unnecessary permission code in controllers. Multiplied request for determining user rights for controls... Maybe I am not getting it right. – klesta Mar 12 '13 at 15:12
  • -1 Using a directive makes perfect sense. Given that the server has been protected, you still need to hide/show things in the UI based on privilege. Using a directive to make it convenient is totally appropriate. – Ronnie Overby Oct 24 '14 at 19:52
  • Yup mis understood his question. I thought he just wanted to know how to evaluate his permissions did not realise he was referring to client side only. – Ray Garner Nov 01 '14 at 14:59