API Resource Authorization
Directory Structure
The Support Directory
Elentra API 3.1 (Elentra ME 1.16.1+) introduces the Support
directory to the top level of the API. This directory is home to the reusable "framework-like" components that are critical to supporting the Elentra API and internal developer APIs. In an effort to increase navigability for developers, this directory has been structured in a way that closely resembles Laravel's Illuminate framework (which the Elentra API is built on top of).
In Elentra API 3.1, new modernized base classes have been provided which can be extended to manage permissions and authorization of API resources. They can be found in the Support\Acl
namespace within the support directory. Additionally a Facade wrapper has also been provided to simplify interacting with the Zend ACL library in a way that integrates better with Laravel applications.
Resources & Assertions
ACL resources and assertions were have been historically defined entrada_acl.inc.php
file. This has changed with Elentra API 3.1+ as they can now be defined inside your API modules. Create a new directory called Acl
in our sandbox module. Inside of the Acl
directory create a new directory named Resources
and another called Assertions
. Classes that you define in these directories should extend the base Assertion
and Resource
classes used by our SandboxPolicy
class.
Defining Permissions
As of Elentra ME 1.15, the Entrada Zend ACL "MOM array" has been replaced with entries in a series of tables within the auth database.
ACL Resource Types
Begin by inserting a new entry into the acl_lu_resource_types
for our new resource type , in this example we will be adding support for authorizing sandbox resources.
ACL Inheritance
In order for our resource to be included in the ACL permission tree, we must also add an entry to the acl_resource_inheritance
table.
Because the sandbox resource is not a child of another resource, we do not specify a value for the acl_resource_type_parent_id
column.
ACL Permissions
We must add a rule to the acl_permissions
table for each role or permission we intend to give access to a resource. The value of the resource_type
field must be identical to the resource type that we added to the acl_lu_resource_types
table. The entity type refers to the combination of groups and roles that we would like to allow access to the resource. Here we have chosen to give access to all administrators who are part of the medtech group. Optionally we can specify the fully qualified name of an assertion class that will perform further authorization checks. Finally, we set the flags for each CRUD permission we would like users to have.
The fully qualified class name should not have Assertion at the end, this will be added automatically by the ACL framework.
Defining Resources
Resource classes are required by Zend ACL in order to resolve the type of resource that is attempting to be authorized. They also allow the developer to specify whether or not the rules should be applied to all resources of a certain type or only a specific instance. In our Sandbox API module we must create a new class called SandboxResource
that extends the base Resource
class in the support directory. We can then override the getResourceId
method to return the value of either the general or the specific resource identifier.
Creating Assertions
Assertions classes provide additional checks to verify whether the specific user has access to the specific resource that is being authorized. In Elentra API 3.1, Eloquent and query builder are now fully supported when defining assertions inside of API an module. In our Sandbox API module we must extend the base Assertion
class in the support directory. We then override the isUserAllowed
method which receives the user that is being authorized; the ID of the resource; the current authorization context; and the CRUD permission that is being checked. isUserAllowed
must either return true or false depending on whether the user has the necessary privileges to access the resource.
Creating Policies
Laravel provides a resource authorization system which it calls Gates. Due to the dynamic nature of gates, we are able to neatly map gate policy methods directly to Elentra's Zend ACL permission system. We begin by extending the base Policy
class provided in the support directory. This class has a protected property that contains a reference to the Entrada_ACL
class.
The Acl
facade provided in the support directory can also be used and is preferable to directly accessing the global $ENTRADA_ACL
instance.
For a standard API resource we will create public methods for each CRUD operation.
The names of the methods defined in policies are arbitrary as Laravel will use the magic __call
method to map gates to policy method calls.
In each method we call the amIAllowed
method on the policy's ACL instance, passing to it a new SandboxResource
instance and the permission being requested. Because the policy in this example is only used when authorizing API requests, we are not required to pass along the $user parameter. The third parameter of amIAllowed
specifies whether or not the rule's assertions should be applied. When performing general authorization without a specific resource instance, we can simply pass false
to disable assertion checks.
Methods that check whether a user is allowed to create a new resource do not receive a second parameter with the resource instance.
Registering Policies
Laravel provides many different ways for resources to be authorized depending on your specific use case. In this example we'll be focusing on using Service Providers, the most commonly used method for registering policies in Elentra. We begin by creating a new class in our Sandbox module's Providers
directory that extends the Illuminate\Foundation\Support\Providers\AuthServiceProvider
base class. This class provides a protected array that maps models to policies, here we have mapped our Sandbox
model to our SandboxPolicy
. Create a new method called boot
that calls the base class' registerPolicies
method.
A service provider'sboot
method will be called automatically by Laravel once the application has finished registering all of its service providers.
Authorizing Requests
The preferred method for authorizing API requests is to call the controller's authorize
helper in each controller's request handler. There are times, however,where a more general or more fine-grained approach is acceptable. The authorize
helper requires a string for its first parmeter that corresponds to the exact method name defined in our SandboxPolicy
above. The second parameter accepts either a model instance or class name and the optional third parameter is an array of any additional arguments you would like to pass to the policy method. The authorize
helper returns true if the current user is allowed to access the resource or throws an exception if they cannot. If an unauthorized exception is thrown, a status code of 403 will automatically be returned in the response.
In our controller's index
and store
methods we pass the Sandbox class instead of a sandbox instance because we do not have a specific ID in these contexts to check against.
Checking Permissions
Authorization can also be performed inline using the auth user instance. The User::can
method takes the same parameters as the controller authorize
helper. However it does not throw an exception and will only return either true or false depending on whether a user can access the resource.
Additional Resources
Last updated