Change record status: 
Project: 
Introduced in branch: 
8.x
Description: 

With the new routing system in Drupal 8, the mechanism for controlling access to routes has changed as well. Routes may now have multiple access checkers on them, and any one of them may pass to grant access.

Simple case:

In mymodule.routing.yml:

mymodule.test:
  path: '/my_module/test'
  defaults:
    _controller: '\Drupal\my_module\TestControllers::test'
  requirements:
    _permission: 'access my module test'

Simple case for access by role:

In mymodule.routing.yml:

mymodule.test:
  path: '/my_module/test'
  defaults:
    _controller: '\Drupal\my_module\TestControllers::test'
  requirements:
    _role: 'authenticated+admin'

The _permission key indicates that the route will be accessible only if the user has the "access my module test" permission. That will suffice in the majority of cases.

However, it is possible to write custom access checkers as well. That requires writing a small class, and adding it to the Container.

namespace Drupal\my_module\Access;

use Drupal\Core\Access\AccessCheckInterface;
use Symfony\Component\Routing\Route;
use Symfony\Component\HttpFoundation\Request;
use Drupal\Core\Session\AccountInterface;

/**
 * Access check for user registration routes.
 */

class WeekdayCheck implements AccessCheckInterface {
  /**
   * This method returns TRUE if this checker will want to control access to this route
   * or FALSE if it doesn't want to be involved in this route.
   */
  public function applies(Route $route) {
    return array_key_exists('_access_my_module_weekday', $route->getRequirements());
  }

  /**
   * This method is only called if applies() returned TRUE above. It may return:
   *   - TRUE: The user should be given access.
   *   - FALSE: The user should NOT be given access.
   *   - NULL: This checker has no input about whether or not access should be granted.
   */
  public function access(Route $route, Request $request, AccountInterface $account) {
    if (strtoupper(date('l')) == strtoupper($route->getRequirement('_access_my_module_weekday'))) {
      return static::ALLOW;
    }
  }
}

In order to allow access, checkers return AccessCheckInterface::ALLOW and AccessCheckInterface::DENY to not give access. AccessCheckIntercace::KILL should just be used if the user should never have access, regardless of the other requirements.
(So in the above example, on the wrong day the user may still be given access by some other checker.) If no checker returns AccessCheckInterface::ALLOW but none return AccessCheckInterface::DENY, access is still denied (that is, default-false).

The access checker must then be registered with the Container:

namespace Drupal\my_module;

class MyModuleBundle extends Bundle {
  public function build(ContainerBuilder $container) {
    $container->register('access_check.my_module.weekday', 'Drupal\mymodule\Access\WeekdayCheck')
      ->addTag('access_check'); // This is the important part.
  }
}

Now, any route in the system may use this new checker like so:

In mymodule.routing.yml:

mymodule.test:
  path: '/my_module/test'
  defaults:
    _controller: '\Drupal\my_module\TestControllers::test'
  requirements:
    _permission: 'access my module test'
    _access_my_module_weekday: 'tuesday'

Now, a user will have access to this route if they have the "access my module test" permission or it is a Tuesday where the server is.

The three common checkers provided by Drupal core are:

  1. _permission: Passes if the user has the specified permission.
  2. _role: Specify one or more role IDs which should have access to the page. If you join them with "+", the user needs to have just one of the roles. If you join them with "," the user needs to have all of the specified roles.
  3. _access: Specify either TRUE or FALSE, and will either always pass or always fail (and block access). This is mostly useful for testing, or for paths that should not have any access control so may just set _access to TRUE to allow anyone in the world access.
Impacts: 
Module developers
Updates Done (doc team, etc.)
Online documentation: 
Not done
Theming guide: 
Not done
Module developer documentation: 
Not done
Examples project: 
Not done
Coder Review: 
Not done
Coder Upgrade: 
Not done
Other: 
Other updates done