Permissions/access caching per node and per user
Access results can store cache metadata like cache tags and cache contexts. As a shortcut AccessResult has two specific methods to apply the correct cache metadata. Different membership in roles or a modified role results in a different set of permissions, use cachePerPermissions() to add a cache context for the hashed permissions. The second method is for the cache context of the current user cachePerUser().

If you get field data from a node or user, add addCacheableDependency($node) or addCacheableDependency($user). 

See this example from the node module:

core/modules/node/node.module, line 938

function node_node_access(NodeInterface $node, $op, $account) {
  $type = $node
    -&gt;bundle();
  switch ($op) {
    case 'create':
      return AccessResult::allowedIfHasPermission($account, 'create ' . $type . ' content');
    case 'update':
      if ($account
        -&gt;hasPermission('edit any ' . $type . ' content', $account)) {
        return AccessResult::allowed()
          -&gt;cachePerPermissions();
      }
      else {
        return AccessResult::allowedIf($account
          -&gt;hasPermission('edit own ' . $type . ' content', $account) &amp;&amp; $account
          -&gt;id() == $node
          -&gt;getOwnerId())
          -&gt;cachePerPermissions()
          -&gt;cachePerUser()
          -&gt;addCacheableDependency($node);
      }