diff --git a/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php b/core/modules/comment/lib/Drupal/comment/Tests/CommentLinksTest.php
index a0f0cdc..110286b 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 $userAccess;
+
   public static function getInfo() {
     return array(
       'name' => 'Comment links',
@@ -32,6 +39,14 @@ public static function getInfo() {
   }
 
   /**
+   * {@inheritdoc}
+   */
+  function setUp() {
+    parent::setUp();
+    $this->userAccess = $this->container->get('user.access');
+  }
+
+  /**
    * Tests comment links.
    *
    * The output of comment links depends on various environment conditions:
@@ -265,7 +280,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->userAccess->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/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php
index b613121..85e7df3 100644
--- a/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php
+++ b/core/modules/system/lib/Drupal/system/Tests/Upgrade/UpgradePathTestBase.php
@@ -11,6 +11,7 @@
 use Drupal\Core\Database\Database;
 use Drupal\Core\DependencyInjection\ContainerBuilder;
 use Drupal\Core\DrupalKernel;
+use Drupal\Core\Session\UserSession;
 use Drupal\simpletest\WebTestBase;
 use Symfony\Component\DependencyInjection\Exception\InvalidArgumentException;
 use Symfony\Component\HttpFoundation\Request;
@@ -145,7 +146,8 @@ protected function setUp() {
     // the global $user session with uid 1 from the new test site.
     drupal_save_session(FALSE);
     // Login as uid 1.
-    $user = db_query('SELECT * FROM {users} WHERE uid = :uid', array(':uid' => 1))->fetchObject();
+    $values = db_query('SELECT * FROM {users} WHERE uid = :uid', array(':uid' => 1))->fetchAssoc();
+    $user = new UserSession($values);
     // Load roles for the user object.
     $roles = array(DRUPAL_AUTHENTICATED_RID => DRUPAL_AUTHENTICATED_RID);
     $result = db_query('SELECT rid, uid FROM {users_roles} WHERE uid = :uid', array(':uid' => 1));
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..1da7e95 100644
--- a/core/modules/user/lib/Drupal/user/RoleStorageController.php
+++ b/core/modules/user/lib/Drupal/user/RoleStorageController.php
@@ -7,8 +7,11 @@
 
 namespace Drupal\user;
 
+use Drupal\Core\Config\ConfigFactory;
 use Drupal\Core\Config\Entity\ConfigStorageController;
+use Drupal\Core\Config\StorageInterface;
 use Drupal\Core\Entity\EntityInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
 
 /**
  * Controller class for user roles.
@@ -18,6 +21,38 @@ class RoleStorageController extends ConfigStorageController {
   /**
    * {@inheritdoc}
    */
+  public static function createInstance(ContainerInterface $container, $entity_type, array $entity_info) {
+    return new static(
+      $entity_type,
+      $entity_info,
+      $container->get('user.access'),
+      $container->get('config.factory'),
+      $container->get('config.storage')
+    );
+  }
+
+  /**
+   * Constructs a RoleStorageController object.
+   *
+   * @param string $entity_type
+   *   The entity type for which the instance is created.
+   * @param array $entity_info
+   *   An array of entity info for the entity type.
+   * @param UserAccessInterface $user_access
+   *   The user access service.
+   * @param \Drupal\Core\Config\ConfigFactory $config_factory
+   *   The config factory service.
+   * @param \Drupal\Core\Config\StorageInterface $config_storage
+   *   The config storage service.
+   */
+  public function __construct($entity_type, array $entity_info, UserAccessInterface $user_access, ConfigFactory $config_factory, StorageInterface $config_storage) {
+    parent::__construct($entity_type, $entity_info, $config_factory, $config_storage);
+    $this->userAccess = $user_access;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
   public function preSave(EntityInterface $entity) {
     if (!isset($entity->weight) && $roles = entity_load_multiple('user_role')) {
       // Set a role weight to make this new role last.
@@ -36,7 +71,7 @@ public function resetCache(array $ids = NULL) {
     parent::resetCache($ids);
 
     // Clear the user access cache.
-    drupal_static_reset('user_access');
+    $this->userAccess->reset();
     drupal_static_reset('user_role_permissions');
   }
 
diff --git a/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php b/core/modules/user/lib/Drupal/user/Tests/UserPermissionsTest.php
index 3fc3b4b..7669e68 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 $userAccess;
+
+  /**
+   * 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,49 @@ 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->userAccess = $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->userAccess->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->userAccess->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');
+    $this->container->get('user.access')->reset();
     drupal_static_reset('user_role_permissions');
-    $this->assertTrue(user_access('administer nodes', $account), 'User now has "administer nodes" permission.');
+    $this->assertTrue($this->userAccess->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->userAccess->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');
+    $this->container->get('user.access')->reset();
     drupal_static_reset('user_role_permissions');
-    $this->assertFalse(user_access('access user profiles', $account), 'User no longer has "access user profiles" permission.');
+    $this->assertFalse($this->userAccess->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 +100,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->userAccess->check('administer news feeds', $this->adminUser), 'The permission was automatically assigned to the administrator role');
   }
 
   /**
@@ -88,12 +108,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->userAccess->check('administer nodes', $account), 'User does not have "administer nodes" permission.');
+    $this->assertTrue($this->userAccess->check('access user profiles', $account), 'User has "access user profiles" permission.');
+    $this->assertTrue($this->userAccess->check('administer site configuration', $account), 'User has "administer site configuration" permission.');
 
     // Change permissions.
     $permissions = array(
@@ -103,8 +123,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->userAccess->check('administer nodes', $account), 'User now has "administer nodes" permission.');
+    $this->assertFalse($this->userAccess->check('access user profiles', $account), 'User no longer has "access user profiles" permission.');
+    $this->assertTrue($this->userAccess->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..e65d75a
--- /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..68bd392
--- /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 \Drupal\Core\Session\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..7007d09 100644
--- a/core/modules/user/user.module
+++ b/core/modules/user/user.module
@@ -412,7 +412,7 @@ function user_password($length = 10) {
  * @param $roles
  *   An array whose values are the role IDs of interest, such as $user->roles.
  *
- * @return
+ * @return array
  *   An array indexed by role ID. Each value is an array whose keys are the
  *   permission strings for the given role ID.
  */
@@ -434,10 +434,9 @@ function user_role_permissions($roles) {
   }
 
   if ($fetch) {
-    // Get from the database permissions that were not in the static variable.
+    // Get from the database permissions that were not in the cache.
     // 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;
     }
@@ -466,39 +465,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,7 +2003,7 @@ function user_role_grant_permissions($rid, array $permissions = array()) {
   }
 
   // Clear the user access cache.
-  drupal_static_reset('user_access');
+  Drupal::service('user.access')->reset();
   drupal_static_reset('user_role_permissions');
 }
 
@@ -2059,7 +2026,7 @@ function user_role_revoke_permissions($rid, array $permissions = array()) {
     ->execute();
 
   // Clear the user access cache.
-  drupal_static_reset('user_access');
+  Drupal::service('user.access')->reset();
   drupal_static_reset('user_role_permissions');
 }
 
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']
