Andrew Cavanagh

Developer.  Project Architect.  Huge Nerd.

(not necessarily in that order)

Managing Access Control Lists (ACL) in Laravel 5.1 is super easy. There’s a free Laracast on it which you should definitely watch if you’re interested in the details of how it works. There’s lots of sugar there if you’re using blade templates, but what if you’re just using Laravel as a backend to an Angularjs app and you want to lock down your API routes with an ACL, and have a custom redirect in Angular for users that aren’t on the list? Here’s one solution using UI-Router.

First, I set up the ACL for my api endpoints as per the video, using the Gate facade for convenience. In the controller I’m returning a 403 if the user doesn’t have access to the resource:

        if (Gate::denies('MyCustomAccessPolicy', $resource_id)){
            return Response::json("User Does Not Have Access To This Resource", 403);
        }

This locks down the api based on the custom rule I set up in AuthServiceProvider, as per the Laracast mentioned above. It’s just a simple bit of logic that checks the current user’s access to a particular resource and returns a boolean.

On the Angular side, in the main config file for the application we have code that looks something like this:

 angular
        .module('app')
        .config(config)     
        .run(function($rootScope) {           
            $rootScope.$on("$stateChangeError", function(event, toState, toParams, fromState, fromParams, error) //this is the important part
            {               
                if (error.status == 403) {
                    $state.go('error.403'); //redirect the user to custom page for this error
                }

            });
        });

We have access to the error message and other data in error, so if we wanted to we could pass that along and make the error page a bit more dynamic. You could also handle the same error code differently depending on where it was thrown - for instance, if we have different ACL policies for different resources that all return a 403 when access is denied, but want to have different redirects or error handling for each resource, we could implement a switch based on the error message or other meta data in error.

It’s worth noting that if your request returns a promise and you’re already catching failures - something like

        function getMyResource(resourceId) {
            return Restangular
                .one('api/v1/resource', resourceId)
                .then(
                success,
                fail
            );
        }

Then in your fail method you’ll need to explicitly reject the promise, or the error will be marked as resolved and $stateChangeError will not fire:

        function fail(response) {
            return $q.reject(response);
        }

comments powered by Disqus