Tập tành Custom Access Check on Routes in Drupal 8/9

11th Jun 2022
Table of contents

Recently in Drupal 8/9, we encountered a situation where we had to restrict access to an existing route based on some custom permissions for a specific role.

The route which we wanted to restrict was block_content.add_form from core block_content module. Below is the reference of the code from block_content.routing.yml:

Currently, there is a single permission Administer block available, which grants access to manage all available block types. So a role that has this permission can manage all block types. But we wanted to limit the creation of some block types for a particular role.

block_content.add_form:
  path: '/block/add/{block_content_type}'
  defaults:
    _controller: '\Drupal\block_content\Controller\BlockContentController::addForm'
    _title_callback: 'Drupal\block_content\Controller\BlockContentController::getAddFormTitle'
  options:
    _admin_route: TRUE
  requirements:
    _permission: 'administer blocks'

To make it more clear, consider the below scenario

  • Let's say we have the following custom block types: Foo (machine name: foo), Bar (machine name: bar), Basic (core).
  • There are two roles Block manager and Block creator with required permissions to administer blocks and Access admin theme.

The objective is to allow a user of a specific role to create a block content of type X if and only if that role has the create X block content permission.

We did this by creating a custom access check for block_content.add_form route in a custom example module.
To start with we defined custom permissions in example.permissions.yml for each block type respectively so that based on it, we can put an access check.

example.permissions.yml

create foo block content:
  title: 'Create Foo block'
create bar block content:
  title: 'Create Bar block'
create basic block content:
  title: 'Create Basic block'

After the permissions are defined, now it's time to register a custom service access_check.block.add for custom access check and register a Route subscriber.

example.services.yml

access_check.block.add:
  class: Drupal\example\Access\ExampleAccessCheck
  arguments: ['@current_user']
  tags:
    - { name: access_check, applies_to: _example_access_check }
example.route_subscriber:
  class: Drupal\example\Routing\RouteSubscriber
  tags:
    - { name: event_subscriber }

Our route subscriber alters the existing route block_content.add_form from the core block module. This is the key step required to add the access checks we want on an existing route.

RouteSubscriber.php

<?php

namespace Drupal\example\Routing;

use Drupal\Core\Routing\RouteSubscriberBase;
use Symfony\Component\Routing\RouteCollection;

/**
 * Listens to the dynamic route events.
 */
class RouteSubscriber extends RouteSubscriberBase {

  /**
   * {@inheritdoc}
   */
  protected function alterRoutes(RouteCollection $collection) {
    $route = $collection->get('block_content.add_form');
    if ($route) {
      $route->setRequirements([
        '_example_access_check' => 'TRUE',
      ]);
    }
  }

}

Route::setRequirement() is used to set custom access checks on the route we want within the alterRoutes function. In our case, it adds check to the block_content.add_form route.

ExampleAccessCheck.php

<?php

namespace Drupal\example\Access;

use Drupal\Core\Access\AccessResult;
use Drupal\Core\Routing\Access\AccessInterface;
use Drupal\Core\Session\AccountInterface;

/**
 * Determines access to for block add pages.
 */
class ExampleAccessCheck implements AccessInterface {

  /**
   * Checks access to the block add page for the block type.
   */
  public function access($block_content_type, AccountInterface $account) {
    return AccessResult::allowedIfHasPermission($account, "create $block_content_type block content");
  }

}

The path in route contains the slug block_content_type which is the machine name of the block type.

$block_content_type is available in access method and this helps to determine if the role has required permissions to access the route for each block type respectively.

example.info.yml

name: Example
description: Example module to demo a custom access check on route.
type: module
core: 8.x

Directory Structure

Custom Access Check on Routes in Drupal 8

Enabling the Example module defines the following permissions:

  • create bar block content
  • create basic block content
  • create foo block content
Custom Access Check on Routes in Drupal 8

 

Now, If we login without either a Block creator or a Block manager role and try to add a custom block of any block type it will simply return Access denied.

Custom Access Check on Routes in Drupal 8

The particular role will be able to create the custom block of type X, only if the Create X block permission is given to the role.

The above example explains how we can add custom Access checks to block_content.add_form route and similarly we can add custom checks to other routes as well.

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ì đã.