How to create a permission with logic I need to create a permission to allow users to see the content overview page (/admin/content) only during business hours (9 AM to 5 PM).

Drupal core comes with the "Access the Content overview page" permission; but I need "Access the Content overview page during work hours".

I know how to create a permission and how to test that the user has the permission. What I don't understand is how to assign some logic to a permission itself (for example, within business hours).

I can do this in mymodule.permissions.yml.

access content overview within business hours:
  title: 'Access the Content overview page within business hours'
  restrict access: TRUE


I can check the user has the permission with \Drupal::currentUser()-&gt;hasPermission('access content overview within business hours').

How can I make the permission return TRUE only during business hours?
How can I check the permission only when the users visits the content overview page?

I can foresee multiple use cases for needing some logic implementation within the permission itself, for example when allowing/restricting access to certain pages depending on whether the environment is development or production, or allowing/restricting access depending on the value of some fields.

- EDIT -

As suggested in the comments, I've started by creating the following three files on my module; but it doesn't work. The CustomAccessChecks::access never gets called.

File: custom_access.services.yml

services:
  custom_access.route_subscriber:
    class: Drupal\custom_access\Routing\AdminRouteSubscriber
    tags:
      - { name: event_subscriber }
  custom_access.access_checker:
    class: Drupal\custom_access\Access\CustomAccessChecks
    tags:
      - { name: access_check }


File: src/Access/CustomAccessChecks.php

&lt;?php

namespace Drupal\custom_access\Access;

use Drupal\Core\Routing\Access\AccessInterface;
use Drupal\Core\Session\AccountInterface;
use Drupal\Core\Access\AccessResultAllowed;
use Symfony\Component\Routing\Route;
use Drupal\Core\Routing\RouteMatchInterface;

class CustomAccessChecks implements AccessInterface {

  /**
   * A custom access check.
   *
   * @param \Drupal\Core\Session\AccountInterface $account
   *   Run access checks for this account.
   */
  public function access(Route $route, RouteMatchInterface $route_match, AccountInterface $account) {
    return AccessResultAllowed::allowedIf((int) $account-&gt;id() === 1);
  }
}


File: AdminRouteSubscriber.php

&lt;?php

namespace Drupal\custom_access\Routing;

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

class AdminRouteSubscriber extends RouteSubscriberBase {


  /**
   * {@inheritdoc}
   */
  public function alterRoutes(RouteCollection $collection) {

    if ($route = $collection-&gt;get('system.admin_content')) {
      $route-&gt;setRequirement('_custom_access', '\Drupal\custom_access\Access\CustomAccessChecks::access');
    }
  }
}


As expected, visiting '/admin/content' as the main administrator $account-&gt;id() === 1 works, but when visiting as another authenticated user, I still can access the page. 

What I'm missing?
When the access to a route doesn't depend uniquely on a single permission, you need to implement what Access checking on routes describes.


Implement a service tagged access_check
Associate it with the route


Since you are altering the route defined from another module, you need to also follow Altering existing routes and adding new routes based on dynamic ones.

example.services.yml

services:
  example.route_subscriber:
    class: Drupal\example\Routing\RouteSubscriber
    tags:
      - { name: event_subscriber }

  example.access_checker:
    class: Drupal\example\Access\CustomAccessCheck
    tags:
      - { name: access_check }


RouteSubscriber.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) {
    if ($route = $collection-&gt;get('system.admin_content')) {
      $route-&gt;setRequirement('_custom_access', 'example.access_checker::access');
    }
  }


CustomAccessCheck.php

namespace Drupal\example\Access;

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

/**
 * Checks access for displaying configuration translation page.
 */
class CustomAccessCheck implements AccessInterface {

  /**
   * A custom access check.
   *
   * @param \Drupal\Core\Session\AccountInterface $account
   *   Run access checks for this account.
   *
   * @return \Drupal\Core\Access\AccessResultInterface
   *   The access result.
   */
  public function access(AccountInterface $account) {
    // Check permissions and combine that with any custom access checking needed. Pass forward
    // parameters from the route and/or request as needed.
    return ($account-&gt;hasPermission('access content overview within business hours') &amp;&amp; $this-&gt;checkTimeAccess()) ? AccessResult::allowed() : AccessResult::forbidden();
  }

}


The checkTimeAccess() method I didn't write should check if the user is trying to access the route during the business hours.

I cannot tell what happens with a route using the _permission requirement when it is altered to use also the _custom_access requirement. I didn't find the Drupal core code handling the access to a route, so I cannot say which requirement is used first.
I didn't also find a way to remove requirements from a route when altering it.