diff --git a/core/core.services.yml b/core/core.services.yml
index f160803..ea0290b 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -681,10 +681,8 @@ services:
       - { name: event_subscriber }
     arguments: ['@authentication']
   current_user:
-    class: Drupal\Core\Session\AccountInterface
-    factory_method: authenticate
-    factory_service: authentication
-    arguments: ['@request']
+    class: Drupal\Core\Session\CurrentUserSession
+    arguments: ['@authentication', '@?request']
     synchronized: true
   asset.css.collection_renderer:
     class: Drupal\Core\Asset\CssCollectionRenderer
diff --git a/core/lib/Drupal/Core/Authentication/AuthenticationManager.php b/core/lib/Drupal/Core/Authentication/AuthenticationManager.php
index d3630c4..3f58518 100644
--- a/core/lib/Drupal/Core/Authentication/AuthenticationManager.php
+++ b/core/lib/Drupal/Core/Authentication/AuthenticationManager.php
@@ -54,6 +54,13 @@ class AuthenticationManager implements AuthenticationProviderInterface, Authenti
   protected $triggeredProviderId = '';
 
   /**
+   * The currently authenticated user account.
+   *
+   * @var \Drupal\Core\Session\UserSession
+   */
+  protected $account;
+
+  /**
    * Adds a provider to the array of registered providers.
    *
    * @param string $provider_id
@@ -83,23 +90,23 @@ public function applies(Request $request) {
    * {@inheritdoc}
    */
   public function authenticate(Request $request) {
-    global $user;
-
-    $account = NULL;
+    if (isset($this->account)) {
+      return $this->account;
+    }
 
-    // Iterate the availlable providers.
+    // Iterate the available providers.
     foreach ($this->getSortedProviders() as $provider_id => $provider) {
       if ($provider->applies($request)) {
         // Try to authenticate with this provider, skipping all others.
-        $account = $provider->authenticate($request);
+        $this->account = $provider->authenticate($request);
         $this->triggeredProviderId = $provider_id;
         break;
       }
     }
 
     // No provider returned a valid account, so set the user to anonymous.
-    if (!$account) {
-      $account = drupal_anonymous_user();
+    if (!$this->account) {
+      $this->account = drupal_anonymous_user();
     }
 
     // No provider was fired, so assume the one with the least priority
@@ -115,9 +122,10 @@ public function authenticate(Request $request) {
     // The global $user object is included for backward compatibility only and
     // should be considered deprecated.
     // @todo Remove this line once global $user is no longer used.
-    $user = $account;
+    global $user;
+    $user = $this->account;
 
-    return $account;
+    return $this->account;
   }
 
   /**
diff --git a/core/lib/Drupal/Core/Session/CurrentUserSession.php b/core/lib/Drupal/Core/Session/CurrentUserSession.php
new file mode 100644
index 0000000..1235420
--- /dev/null
+++ b/core/lib/Drupal/Core/Session/CurrentUserSession.php
@@ -0,0 +1,74 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\Core\Session\CurrentUserSession.
+ */
+
+namespace Drupal\Core\Session;
+
+use Drupal\Core\Authentication\AuthenticationManagerInterface;
+use Symfony\Component\HttpFoundation\Request;
+
+/**
+ * A factory class to get the currently authenticated user.
+ */
+class CurrentUserSession {
+
+  /**
+   * The authentication manager.
+   *
+   * @var \Drupal\Core\Authentication\AuthenticationManagerInterface
+   */
+  protected $authManager;
+
+  /**
+   * The current request.
+   *
+   * @var \Symfony\Component\HttpFoundation\Request
+   */
+  protected $request;
+
+  /**
+   * The current user account.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $account;
+
+  /**
+   * Constructs a CurrentUserSession object.
+   *
+   * @param \Drupal\Core\Authentication\AuthenticationManagerInterface $auth_manager
+   *   The authentication manager.
+   */
+  public function __construct(AuthenticationManagerInterface $auth_manager, Request $request) {
+    $this->authManager = $auth_manager;
+    $this->request = $request;
+  }
+
+  /**
+   * Gets the current account.
+   *
+   * @return \Drupal\Core\Session\AccountInterface
+   *   The current account.
+   */
+  public function get() {
+    if (empty($this->account)) {
+      $this->set($this->authManager->authenticate($this->request));
+    }
+
+    return $this->account;
+  }
+
+  /**
+   * Sets the current user.
+   *
+   * @param \Drupal\Core\Session\AccountInterface $account
+   *   The account to set.
+   */
+  public function set(AccountInterface $account) {
+    $this->account = $account;
+  }
+
+}
