how to write a directive that restricts post requests

244 Views Asked by At

I am adding an new user profile that has read-only access to my restful app.

My app only uses get and post requests (no put, delete, etc.)

A user with read-only access cannot create, edit, or delete any data (can only view data). In other words, cannot perform any POST requests - only GET requests can be made by this user.

I need to write a directive that will intercept any post request and produce an error ("not allowed for read-only access") if a button that makes a post request is clicked.

My goal is to add the directive as an attribute in a form (for example). Like so:

<form restrictReadOnly name="form1" class="form-horizontal" novalidate>...

I have started, but not sure where to go from here:

directive('restrictReadOnly', function() {
    'use strict';

    return {
        restrict: 'A',
        controller: 'restrictReadOnlyCtrl',
        link: function(scope, element, attrs) {
        //.................
2

There are 2 best solutions below

0
On BEST ANSWER

There are a couple points to be made here, I think. I'll do my best to answer your question.

Firstly, I just want to point out that restricting access on the front-end alone is not usually a good security practice (any code on the front-end can be manipulated by the user. If the user still has POST privileges on the server, even if it is restricted on the client, there are ways to get around that.) Therefore, if this is a serious question about restricting user access, I would definitely recommend doing that on the server, and not on the client.

Secondly, I'll answer the main question. There are several ways to go about intercepting a request. The usual method is to use an interceptor (blog post by Ben Nadel). Since your question requires you to use a directive for some reason, I might suggest sending an event through $rootScope on form submit, and the HTTP interceptor will look at that event and complete or stop the request. However, I think the better approach would just be to use an interceptor (and no directive) if all you're looking to do is restrict all POST requests.

So, your directive:

// inject $rootScope as a dependency first
link: function(scope, $el, attrs) {
  $el.on('submit', stop);

  function stop() {
    e.preventDefault();
    $rootScope.$broadcast('request.restricted', $el);

    return false;
  }
}

Then, your interceptor:

config.$inject = ['$httpProvider'];

app.config(config);

function config($httpProvider) {
  $httpProvider.interceptors.push(interceptor);

  interceptor.$inject = ['$q', '$rootScope'];

  function interceptor($q, $rootScope) {
    var cancel = $q.defer();

    return {
      request: request
    };

    function request(config) {
      $rootScope.$on('request.restricted', stop);

      function stop() {
        config.timeout = cancel.promise;
      }

      return config;
    }
  }
}

See this question that says how to stop a request from completing.

However

What I would really recommend is just using an interceptor to check if the method used is POST, and if so, stop the request. No directive needed.

config.$inject = ['$httpProvider'];

app.config(config);

function config($httpProvider) {
  $httpProvider.interceptors.push(interceptor);

  interceptor.$inject = ['$q'];

  function interceptor($q) {
    var cancel = $q.defer();

    return {
      request: request
    };

    function request(config) {
      if(config.method.toLowerCase() === 'post') {
        config.timeout = cancel.promise;
      }

      return config;
    }
  }
}

Better yet, do it on the server

0
On

Well, I am not pretty sure how we can achieve this using a directive. However, I have an alternative, please see if it can resolve your problem.

In place of directive add a class or data attribute to such forms. Let us add a class "restrictReadOnly"

Now, in your html bind those functions that make a post call, let us say something like the following

$scope.postSubmit = function() {
     // now get your form element which was under process.
     // Check if that class is specified, if yes do error handling, else continue;
};