Magento 2: How to create an admin controller and a new ACL

In this tutorial, you will learn how to create a new backend controller and ACL on Magento 2.

Magento’s backend is the place where the store owner can manage everything related to his online business. In the backend, everything is extendible — we can create new configurations, roles, pages, menus, components, and so on. When creating a new feature, it is important to always follow Magento’s best practices to keep our store secure from non-authorised users.

On this tutorial, you will learn how to:

  1. Create and install a new module
  2. Registering a new backend controller
  3. Adding a new ACL
  4. Limiting access to a controller using an ACL
  5. Download the code

1. Create and install a new module

Before we can add a new controller to our Magento backend, we first need to create a new custom module. On Magento 2, a module only needs 2 basic files: registration.php and etc/module.xml. In our case, these files  will be created in the path app/code/Examples/Acl , where “Examples” is the vendor name for our module and “Acl” is the module name. You probably do not have any of these folders so you should create them.

Here is the content for both files:

Now that our module has been created, lets set it up by running the command php bin/magento setup:upgrade and then enable it with
php bin/magento module:enable Examples_Acl.

2. Registering a new backend controller

Although backend controllers are very similar to their frontend counterparts, they will extend from the class \Magento\Backend\App\Action , which handles all security procedures necessary in order to make the backend accessible only  for authenticated users. Registering a new backend controller requires the creation of two files:

etc/adminhtml/routes.xml  – As its name suggests, this file initializes the route for the adminhtml area. We will use this file to configure a route name for our module.

Controler/Adminhtml/Index/Index.php  – The controller action.

The code for both files is:

Before we can test our code, we need to remove the secret key from our URLs, otherwise we won’t be able to directly access our new controller. Magento adds automatically a secret key to each backend url in order to prevent against CSRF attacks. While this option is enabled, we won’t be able to directly access a controller just by typing its URL in the address bar.

Log-in to your Magento backend and go to Stores > Configuration > Advanced > Admin > Security . Set the option Add security keys to URLs as no.

Now we just need to run the command php bin/magento cache:clean to clear the cache and our new controller should be accessible. This is how Magento builds the URLs for backend controllers:

<store_path>/<backend_path>/<route_name>/<controller_name>/<action_name>

Note: if your action name is index, you do not need to add it to the URL

Our route was defined as exampleacl in the routes.xml file. Our controller name is Index , which is also the name of our action, so our controller URL should look like this:

http://your-magento-site.com/admin-folder/exampleacl/index/index

You should see a blank page with the following message:

It is also possible to change the execute() function of the controller class in order to load Magento’s interface with a blank page:

Your page now will look like this:

3. Adding a new ACL

By creating a new ACL (Access Control List) we can limit the access to our new controller, allowing only certain groups of users (roles) to have access to its contents. By default, Magento 2 has only one admin role – Administrators. All users under this role have access to all backend features, so before creating our new ACL, we first need to create a new role and a new user – we will need them later to verify if our new ACL is working.

Navigate to System > Permissions > User Roles and click on Add New Role. The new role name will be Example. Now, under the tab Role Resources, enable access to all resources:

Save the new role.

Go to System > Permissions > All Users and add a new user. Under the tab User Role , select the new role previously created.

Now that we are done creating a new user, let’s add the acl.xml to our module:

Note that on this file we have a bunch of nested resources. The resource Magento_Backend::admin should always be the parent node by default, while Magento_Backend::dashboard already exists (it was initially defined on vendor/magento/module-backend/etc/acl.xml), so we created just two new resources: Examples_Acl::exampleparent and Examples_Acl::examplechild.

After cleaning Magento’s cache using php bin/magento cache:clean, our new ACLs should appear under System > Permissions > User Roles > Example > Role Resources > Dashboard :

4. Limiting access to a controller using an ACL

For the last part of this tutorial, we will add the following function to the file app/code/Examples/Controllers/Adminhtml/Index/Index.php :

The function _isAllowed() must always return a bool of whether that controller can be displayed.
$this->_authorization is an instance of \Magento\Framework\AuthorizationInterface and is used to verify if a given ACL is enabled/disabled in the role of the current user.

Now that we have everything set up, log-in to your Magento admin using the new user previously created. If you try to access our index controller using the URL http://your-magento-site.com/admin-folder/exampleacl/index/index , you should be able to access the page without any problem. This happens because the ACLs are nested, so if the parent ACL is enabled, all of its children will be enabled as well. When we created the ACL, it was under Dashboard , so if we want to disable the access to our controller, we need to disable the resource Dashboard first.

Note: In the same way, if a child resource is enabled, all parent resources will be set to enabled as well.

If you disable the resource Dashboard for the current user role and try to access our index controller again, the following error message will be displayed:

5. Download the code

You can download the entire code for this tutorial from my GitHub account: