diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php
index a0f0cdc..108090c 100644
--- a/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php
+++ b/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php
@@ -23,6 +23,13 @@ class CommentLinksTest extends CommentTestBase {
    */
   public static $modules = array('views');
 
+  /**
+   * A UserAccess service object used for checking permissions within this test.
+   *
+   * @var \Drupal\user\UserAccess
+   */
+  protected $accessService;
+
   public static function getInfo() {
     return array(
       'name' => 'Comment links',
@@ -31,6 +38,12 @@ public static function getInfo() {
     );
   }
 
+  function setUp() {
+    parent::setUp();
+
+    $this->accessService = $this->container->get('user.access');
+  }
+
   /**
    * Tests comment links.
    *
@@ -265,7 +278,7 @@ function assertCommentLinks(array $info) {
         // authenticated users are allowed to post comments.
         // @see theme_comment_post_forbidden()
         if (!$this->loggedInUser) {
-          if (user_access('post comments', $this->web_user)) {
+          if ($this->accessService->check('post comments', $this->web_user)) {
             // The note depends on whether users are actually able to register.
             if ($info['user_register'] != USER_REGISTER_ADMINISTRATORS_ONLY) {
               $this->assertText('Log in or register to post comments');
diff --git a/core/modules/user/lib/Drupal/user/Access/PermissionAccessCheck.php b/core/modules/user/lib/Drupal/user/Access/PermissionAccessCheck.php
index 519ba86..d1a8dd4 100644
--- a/core/modules/user/lib/Drupal/user/Access/PermissionAccessCheck.php
+++ b/core/modules/user/lib/Drupal/user/Access/PermissionAccessCheck.php
@@ -8,6 +8,7 @@
 namespace Drupal\user\Access;
 
 use Drupal\Core\Access\AccessCheckInterface;
+use Drupal\user\UserAccessInterface;
 use Symfony\Component\Routing\Route;
 use Symfony\Component\HttpFoundation\Request;
 
@@ -17,6 +18,23 @@
 class PermissionAccessCheck implements AccessCheckInterface {
 
   /**
+   * The user access service.
+   *
+   * @var \Drupal\user\UserAccessInterface
+   */
+  protected $userAccess;
+
+  /**
+   * Constructs a PermissionAccessCheck object.
+   *
+   * @param \Drupal\user\UserAccessInterface $user_access
+   *   The user access service.
+   */
+  public function __construct(UserAccessInterface $user_access) {
+    $this->userAccess = $user_access;
+  }
+
+  /**
    * Implements AccessCheckInterface::applies().
    */
   public function applies(Route $route) {
@@ -28,9 +46,8 @@ public function applies(Route $route) {
    */
   public function access(Route $route, Request $request) {
     $permission = $route->getRequirement('_permission');
-    // @todo Replace user_access() with a correctly injected and session-using
-    //   alternative.
-    // If user_access() fails, return NULL to give other checks a chance.
-    return user_access($permission) ? static::ALLOW : static::DENY;
+    // If the check fails, return NULL to give other checks a chance.
+    return $this->userAccess->check($permission, $GLOBALS['user']) ? static::ALLOW : static::DENY;
   }
+
 }
diff --git a/core/modules/user/lib/Drupal/user/RoleStorageController.php b/core/modules/user/lib/Drupal/user/RoleStorageController.php
index 680b412..7da522e 100644
--- a/core/modules/user/lib/Drupal/user/RoleStorageController.php
+++ b/core/modules/user/lib/Drupal/user/RoleStorageController.php
@@ -36,8 +36,7 @@ public function resetCache(array $ids = NULL) {
     parent::resetCache($ids);
 
     // Clear the user access cache.
-    drupal_static_reset('user_access');
-    drupal_static_reset('user_role_permissions');
+    \Drupal::service('user.access')->reset();
   }
 
   /**
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php b/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php
index 3fc3b4b..79b507c 100644
--- a/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php
+++ b/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php
@@ -10,7 +10,26 @@
 use Drupal\simpletest\WebTestBase;
 
 class UserPermissionsTest extends WebTestBase {
-  protected $admin_user;
+
+  /**
+   * A UserAccess service object used for checking permissions within this test.
+   *
+   * @var \Drupal\user\UserAccess
+   */
+  protected $accessService;
+
+  /**
+   * A user object with administrative permissions.
+   *
+   * @var \Drupal\user\Plugin\Core\Entity\User
+   */
+  protected $adminUser;
+
+  /**
+   * The role ID of an administrative role created per test run.
+   *
+   * @var int
+   */
   protected $rid;
 
   public static function getInfo() {
@@ -24,48 +43,47 @@ public static function getInfo() {
   function setUp() {
     parent::setUp();
 
-    $this->admin_user = $this->drupalCreateUser(array('administer permissions', 'access user profiles', 'administer site configuration', 'administer modules', 'administer users'));
+    $this->accessService = $this->container->get('user.access');
+    $this->adminUser = $this->drupalCreateUser(array('administer permissions', 'access user profiles', 'administer site configuration', 'administer modules', 'administer users'));
 
     // Find the new role ID.
-    $all_rids = $this->admin_user->roles;
+    $all_rids = $this->adminUser->roles;
     unset($all_rids[array_search(DRUPAL_AUTHENTICATED_RID, $all_rids)]);
     $this->rid = reset($all_rids);
   }
 
   /**
-   * Change user permissions and check user_access().
+   * Change user permissions and check $this->accessService->check().
    */
   function testUserPermissionChanges() {
-    $this->drupalLogin($this->admin_user);
+    $this->drupalLogin($this->adminUser);
     $rid = $this->rid;
-    $account = $this->admin_user;
+    $account = $this->adminUser;
 
     // Add a permission.
-    $this->assertFalse(user_access('administer nodes', $account), 'User does not have "administer nodes" permission.');
+    $this->assertFalse($this->accessService->check('administer nodes', $account), 'User does not have "administer nodes" permission.');
     $edit = array();
     $edit[$rid . '[administer nodes]'] = TRUE;
     $this->drupalPost('admin/people/permissions', $edit, t('Save permissions'));
     $this->assertText(t('The changes have been saved.'), 'Successful save message displayed.');
-    drupal_static_reset('user_access');
-    drupal_static_reset('user_role_permissions');
-    $this->assertTrue(user_access('administer nodes', $account), 'User now has "administer nodes" permission.');
+    $this->container->get('user.access')->reset();
+    $this->assertTrue($this->accessService->check('administer nodes', $account), 'User now has "administer nodes" permission.');
 
     // Remove a permission.
-    $this->assertTrue(user_access('access user profiles', $account), 'User has "access user profiles" permission.');
+    $this->assertTrue($this->accessService->check('access user profiles', $account), 'User has "access user profiles" permission.');
     $edit = array();
     $edit[$rid . '[access user profiles]'] = FALSE;
     $this->drupalPost('admin/people/permissions', $edit, t('Save permissions'));
     $this->assertText(t('The changes have been saved.'), 'Successful save message displayed.');
-    drupal_static_reset('user_access');
-    drupal_static_reset('user_role_permissions');
-    $this->assertFalse(user_access('access user profiles', $account), 'User no longer has "access user profiles" permission.');
+    $this->container->get('user.access')->reset();
+    $this->assertFalse($this->accessService->check('access user profiles', $account), 'User no longer has "access user profiles" permission.');
   }
 
   /**
    * Test assigning of permissions for the administrator role.
    */
   function testAdministratorRole() {
-    $this->drupalLogin($this->admin_user);
+    $this->drupalLogin($this->adminUser);
     $this->drupalGet('admin/config/people/accounts');
 
     // Set the user's role to be the administrator role.
@@ -80,7 +98,7 @@ function testAdministratorRole() {
     // Aggregator depends on file module, enable that as well.
     $edit['modules[Core][file][enable]'] = TRUE;
     $this->drupalPost('admin/modules', $edit, t('Save configuration'));
-    $this->assertTrue(user_access('administer news feeds', $this->admin_user), 'The permission was automatically assigned to the administrator role');
+    $this->assertTrue($this->accessService->check('administer news feeds', $this->adminUser), 'The permission was automatically assigned to the administrator role');
   }
 
   /**
@@ -88,12 +106,12 @@ function testAdministratorRole() {
    */
   function testUserRoleChangePermissions() {
     $rid = $this->rid;
-    $account = $this->admin_user;
+    $account = $this->adminUser;
 
     // Verify current permissions.
-    $this->assertFalse(user_access('administer nodes', $account), 'User does not have "administer nodes" permission.');
-    $this->assertTrue(user_access('access user profiles', $account), 'User has "access user profiles" permission.');
-    $this->assertTrue(user_access('administer site configuration', $account), 'User has "administer site configuration" permission.');
+    $this->assertFalse($this->accessService->check('administer nodes', $account), 'User does not have "administer nodes" permission.');
+    $this->assertTrue($this->accessService->check('access user profiles', $account), 'User has "access user profiles" permission.');
+    $this->assertTrue($this->accessService->check('administer site configuration', $account), 'User has "administer site configuration" permission.');
 
     // Change permissions.
     $permissions = array(
@@ -103,8 +121,8 @@ function testUserRoleChangePermissions() {
     user_role_change_permissions($rid, $permissions);
 
     // Verify proper permission changes.
-    $this->assertTrue(user_access('administer nodes', $account), 'User now has "administer nodes" permission.');
-    $this->assertFalse(user_access('access user profiles', $account), 'User no longer has "access user profiles" permission.');
-    $this->assertTrue(user_access('administer site configuration', $account), 'User still has "administer site configuration" permission.');
+    $this->assertTrue($this->accessService->check('administer nodes', $account), 'User now has "administer nodes" permission.');
+    $this->assertFalse($this->accessService->check('access user profiles', $account), 'User no longer has "access user profiles" permission.');
+    $this->assertTrue($this->accessService->check('administer site configuration', $account), 'User still has "administer site configuration" permission.');
   }
 }
diff --git a/core/modules/user/lib/Drupal/user/UserAccess.php b/core/modules/user/lib/Drupal/user/UserAccess.php
new file mode 100644
index 0000000..ba0c53c
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/UserAccess.php
@@ -0,0 +1,114 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\UserAccess.
+ */
+
+namespace Drupal\user;
+
+use Drupal\Core\Database\Connection;
+use Drupal\Core\Session\AccountInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+
+/**
+ * Defines the user access service.
+ */
+class UserAccess implements UserAccessInterface {
+
+  /**
+   * A cache of permissions for a user uid.
+   *
+   * @var array
+   */
+  protected $permissionCache = array();
+
+  /**
+   * A cache of permissions within roles.
+   *
+   * @var array
+   */
+  protected $roleCache = array();
+
+  /**
+   * The database connection object for this service.
+   *
+   * @var \Drupal\Core\Database\Connection
+   */
+  protected $database;
+
+  /**
+   * Constructs a new UserAccess service object.
+   *
+   * @param \Drupal\Core\Database\Connection $database
+   *   The database connection object to be used by this service.
+   */
+  public function __construct(Connection $database) {
+    $this->database = $database;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function check($string, AccountInterface $account) {
+    $id = $account->id();
+
+    // User #1 has all privileges.
+    if ($id == 1) {
+      return TRUE;
+    }
+
+    // We cache the user's permissions for performance reasons.
+    if (!isset($this->permissionCache[$id])) {
+      $this->permissionCache[$id] = array();
+      foreach ($this->userRolePermissions($account->getRoles()) as $permissions) {
+        $this->permissionCache[$id] += $permissions;
+      }
+    }
+
+    return isset($this->permissionCache[$id][$string]);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function reset() {
+    $this->permissionCache = array();
+    $this->roleCache = array();
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function userRolePermissions(array $roles) {
+    $role_permissions = $fetch = array();
+
+    foreach ($roles as $rid) {
+      if (isset($this->roleCache[$rid])) {
+        $role_permissions[$rid] = $this->roleCache[$rid];
+      }
+      else {
+        // Add this rid to the list of those needing to be fetched.
+        $fetch[] = $rid;
+        // Prepare in case no permissions are returned.
+        $this->roleCache[$rid] = array();
+      }
+    }
+
+    if ($fetch) {
+      // Get from the database permissions that were not in the cache.
+      // Only role IDs with at least one permission assigned will return rows.
+      $result = $this->database->query("SELECT rid, permission FROM {role_permission} WHERE rid IN (:fetch)", array(':fetch' => $fetch));
+      foreach ($result as $row) {
+        $this->roleCache[$row->rid][$row->permission] = TRUE;
+      }
+      foreach ($fetch as $rid) {
+        // For every rid, we know we at least assigned an empty array.
+        $role_permissions[$rid] = $this->roleCache[$rid];
+      }
+    }
+
+    return $role_permissions;
+  }
+
+}
diff --git a/core/modules/user/lib/Drupal/user/UserAccessInterface.php b/core/modules/user/lib/Drupal/user/UserAccessInterface.php
new file mode 100644
index 0000000..56fe75f
--- /dev/null
+++ b/core/modules/user/lib/Drupal/user/UserAccessInterface.php
@@ -0,0 +1,51 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\UserAccessInterface.
+ */
+
+namespace Drupal\user;
+
+use Drupal\Core\Session\AccountInterface;
+
+/**
+ * Defines the user access service interface.
+ */
+interface UserAccessInterface {
+
+  /**
+   * Determines whether the given user has a given privilege.
+   *
+   * @param $string
+   *   The permission, such as "administer nodes", being checked for.
+   * @param AccountInterface $account
+   *   The account to check.
+   *
+   * @return
+   *   Boolean TRUE if the account passed has the requested permission.
+   *
+   * All permission checks in Drupal should go through this function. This way,
+   * we guarantee consistent behavior, and ensure that the superuser can perform
+   * all actions.
+   */
+  public function check($string, AccountInterface $account);
+
+  /**
+   * Resets the permissions and roles caches.
+   */
+  public function reset();
+
+  /**
+   * Determines the permissions for one or more roles.
+   *
+   * @param array $roles
+   *   An array whose keys are the role IDs of interest, such as $user->roles.
+   *
+   * @return array
+   *   An array indexed by role ID. Each value is an array whose keys are the
+   *   permission strings for the given role ID.
+   */
+  public function userRolePermissions(array $roles);
+
+}
diff --git a/core/modules/user/user.module b/core/modules/user/user.module
index 1c7633d..abc66b6 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -417,37 +417,7 @@ function user_password($length = 10) {
  *   permission strings for the given role ID.
  */
 function user_role_permissions($roles) {
-  $cache = &drupal_static(__FUNCTION__, array());
-
-  $role_permissions = $fetch = array();
-
-  foreach ($roles as $rid) {
-    if (isset($cache[$rid])) {
-      $role_permissions[$rid] = $cache[$rid];
-    }
-    else {
-      // Add this rid to the list of those needing to be fetched.
-      $fetch[] = $rid;
-      // Prepare in case no permissions are returned.
-      $cache[$rid] = array();
-    }
-  }
-
-  if ($fetch) {
-    // Get from the database permissions that were not in the static variable.
-    // Only role IDs with at least one permission assigned will return rows.
-    $result = db_query("SELECT rid, permission FROM {role_permission} WHERE rid IN (:fetch)", array(':fetch' => $fetch));
-
-    foreach ($result as $row) {
-      $cache[$row->rid][$row->permission] = TRUE;
-    }
-    foreach ($fetch as $rid) {
-      // For every rid, we know we at least assigned an empty array.
-      $role_permissions[$rid] = $cache[$rid];
-    }
-  }
-
-  return $role_permissions;
+  return Drupal::service('user.access')->userRolePermissions($roles);
 }
 
 /**
@@ -466,39 +436,7 @@ function user_role_permissions($roles) {
  * can perform all actions.
  */
 function user_access($string, AccountInterface $account = NULL) {
-  global $user;
-
-  if (!isset($account)) {
-    $account = $user;
-  }
-
-  // Make sure we are working with the BC decorator.
-  $account = $account instanceof User ? $account->getBCEntity() : $account;
-
-  // User #1 has all privileges:
-  if ($account->uid == 1) {
-    return TRUE;
-  }
-
-  // To reduce the number of SQL queries, we cache the user's permissions
-  // in a static variable.
-  // Use the advanced drupal_static() pattern, since this is called very often.
-  static $drupal_static_fast;
-  if (!isset($drupal_static_fast)) {
-    $drupal_static_fast['perm'] = &drupal_static(__FUNCTION__);
-  }
-  $perm = &$drupal_static_fast['perm'];
-  if (!isset($perm[$account->uid])) {
-    $role_permissions = user_role_permissions($account->getRoles());
-
-    $perms = array();
-    foreach ($role_permissions as $one_role) {
-      $perms += $one_role;
-    }
-    $perm[$account->uid] = $perms;
-  }
-
-  return isset($perm[$account->uid][$string]);
+  return Drupal::service('user.access')->check($string, isset($account) ? $account : $GLOBALS['user']);
 }
 
 /**
@@ -2036,8 +1974,7 @@ function user_role_grant_permissions($rid, array $permissions = array()) {
   }
 
   // Clear the user access cache.
-  drupal_static_reset('user_access');
-  drupal_static_reset('user_role_permissions');
+  Drupal::service('user.access')->reset();
 }
 
 /**
@@ -2059,8 +1996,7 @@ function user_role_revoke_permissions($rid, array $permissions = array()) {
     ->execute();
 
   // Clear the user access cache.
-  drupal_static_reset('user_access');
-  drupal_static_reset('user_role_permissions');
+  Drupal::service('user.access')->reset();
 }
 
 function user_multiple_cancel_confirm($form, &$form_state) {
diff --git a/core/modules/user/user.services.yml b/core/modules/user/user.services.yml
index 468955d..4e87bbc 100644
--- a/core/modules/user/user.services.yml
+++ b/core/modules/user/user.services.yml
@@ -1,6 +1,7 @@
 services:
   access_check.permission:
     class: Drupal\user\Access\PermissionAccessCheck
+    arguments: ['@user.access']
     tags:
       - { name: access_check }
   access_check.user.register:
@@ -21,3 +22,6 @@ services:
   user.autocomplete:
     class: Drupal\user\UserAutocomplete
     arguments: ['@database', '@config.factory']
+  user.access:
+    class: Drupal\user\UserAccess
+    arguments: ['@database']
