Tập tành Restricting Access to Drupal 8/9 Controllers

11th Jun 2022
Table of contents

Controllers in Drupal 8/9 are the equivalent of hook_menu in Drupal 7. A controller lets you define a URL and what content or data should appear at that URL. If you’re like me, limiting access to my controllers is sometimes an afterthought. Limiting access is important because it defines who can and can’t see a page.

Controllers are defined in a YAML file called module_name.routing.yml. Access and permission rules are defined in the the module_name.routing.yml under _requirements. Most of the code examples will be from a module_name.routing.yml file added to my_module in the top level.

Note: There is a lot of existing documentation on how to create controllers in Drupal 8, so I won’t focus on that here.

I’ve outlined some of the most useful approaches for limiting access below. You can jump straight to the most relevant section using the following links: limit by permission, limit by role, limit by one-off custom code, limit by custom access service.

Limit by permission

In this case, a permission from the Drupal permissions page is given. Permissions can be found at /admin/people/permissions. Finding the exact permission name can be tricky. Look for module.permissions.yml files in the module providing the permission.

my_module.dashboard:
  path: 'dashboard'
  defaults:
    _controller: '\Drupal\my_module\Controller\DashboardController::content'
    _title: 'Dashboard'
  requirements:
    _permission: 'access content'

_permission: 'THE PERMISSION NAME'

Limit by role

You can also limit access by role. This would be useful in cases where users of a specific role will be the only ones needing access to your controller. You can define user roles at /admin/people/roles.

my_module.dashboard:
  path: 'dashboard'
  defaults:
    _controller: '\Drupal\my_module\Controller\DashboardController::content'
    _title: 'Dashboard'
  requirements:
    _role: 'administrator'

_role: 'THE ROLE NAME'

You can specify multiple roles using "," for AND and "+" for OR logic.

Limit by one-off custom code

In cases where you have custom access requirements, adding an access method to your controller might make sense. In this example, the page should not be viewed before a specified date.

my_module.dashboard:
  path: 'dashboard'
  defaults:
    _controller: '\Drupal\my_module\Controller\DashboardController::content'
    _title: 'Dashboard'
  requirements:
   _custom_access: '\Drupal\my_module\Controller\DashboardController::access

_custom_access: '\Drupal\my_module\Controller\DashboardController::access

The access method in my controller would look like:

<?php
namespace Drupal\my_module\Controller;
 
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Controller\ControllerBase;
 
/**
 * Defines the Dashboard controller.
 */
class DashboardController extends ControllerBase { {
 
 /**
  * Returns content for this controller.
  */
 public function content() {
   $build = [];
   return $build;
 }
 
 /**
  * Checks access for this controller.
  */
 public function access() {
   // Don’t allow access before Friday, November 25, 2016.
   $today = date("Y-m-d H:i:s");
   $date = "2016-11-25 00:00:00";
   if ($date < $today) {
     // Return 403 Access Denied page.  
     return AccessResult::forbidden();
    }
    return AccessResult::allowed();
  }
}

Limit by custom access service

This is similar to having an access method in your controller, but allows the code to be reused across many controllers. This is ideal when you are doing the same access check across many controllers.

my_module.dashboard:
  path: 'dashboard'
  defaults:
    _controller: '\Drupal\my_module\Controller\DashboardController::content'
    _title: 'Dashboard'
  requirements:
    _custom_access_check: 'TRUE'

_custom_access_check: 'TRUE'

Proving the _custom_access_check service requires creating two files in my_module.

my_module/my_module.services.yml (defines the Access service and where to find our Access class)

services:
  my_module.custom_access_check:
    class: Drupal\my_module\Access\CustomAccessCheck
    arguments: ['@current_user']
    tags:
      - { name: access_check, applies_to: _custom_access_check }

my_module/src/Access/CustomAccessCheck.php

<?php
namespace Drupal\my_module\Access;
 
use Drupal\Core\Access\AccessResult;
use Drupal\Core\Routing\Access\AccessInterface;
use Drupal\Core\Session\AccountInterface;
 
/**
 * Class CustomAccessCheck.
 *
 * @package Drupal\my_module\Access
 */
class CustomAccessCheck implements AccessInterface {
 
  /**
   * A custom access check.
   *
   * @param \Drupal\Core\Session\AccountInterface $account
   *   Run access checks for the logged in user.
   */
  public function access(AccountInterface $account) {
    // User has a profile field defining their favorite color.
    if ($account->field_color->hasField() && !$account->field_color->isEmpty() && $account->field_color->getString() === 'blue') {
      // If the user's favorite color is blue, give them access.
      return AccessResult::allowed();
    }
    return AccessResult::forbidden();
  }
 
}

While the above covers some of the most useful ways to restrict access to a controller, there are additional options. Drupal.org has a couple of good resources including Structure of Routes and Access Checking on Routes.

Bạn thấy bài viết này như thế nào?
0 reactions

Add new comment

Image CAPTCHA
Enter the characters shown in the image.
Câu nói tâm đắc: “Điều tuyệt với nhất trong cuộc sống là làm được những việc mà người khác tin là không thể!”

Related Articles

Master list (in progress) of how to get parts of fields for use in Twig templates. I’m always having to look these up, so I thought I’d hash them out and write them down.

Litespeed Cache là plugin WordPress dùng để kết hợp với Web Server LiteSpeed nhằm tăng tốc website WordPress của bạn gấp nhiều lần

In this article, we are going to see how some tools & libraries will make people's lives easier during the development & code review process.

In this tutorial, you will learn how to improve the custom code, theme and module, and general code development by using the pre-commit hook on git

Trước khi tìm hiểu xem PHP Code Sniffer là gì thì các bạn cần phải nắm được coding convention là gì đã.