diff --git a/core/lib/Drupal/Core/Authentication/AuthenticationManager.php b/core/lib/Drupal/Core/Authentication/AuthenticationManager.php
index 1a7ca6e..d4a4eed 100644
--- a/core/lib/Drupal/Core/Authentication/AuthenticationManager.php
+++ b/core/lib/Drupal/Core/Authentication/AuthenticationManager.php
@@ -88,8 +88,22 @@ public function authenticate(Request $request) {
 
     $account = NULL;
 
-    // Iterate the availlable providers.
-    foreach ($this->getSortedProviders() as $provider_id => $provider) {
+    $auth_providers = $this->getSortedProviders();
+
+    // If authentication is triggered after routing, restrict the allowed
+    // providers to the ones specified in the routes _auth option.
+    //
+    // @todo Duplicates AuthenticationEnhancer by reducing providers to the
+    // default one if no _auth was specified. This restriction will be removed
+    // by https://www.drupal.org/node/2286971
+    if ($request->attributes->has(RouteObjectInterface::ROUTE_OBJECT)) {
+      $route = $request->attributes->get(RouteObjectInterface::ROUTE_OBJECT);
+      $allowed_providers = $route->getOption('_auth') ? $route->getOption('_auth') : array($this->defaultProviderId());
+      $auth_providers = array_intersect_key($auth_providers, array_flip($allowed_providers));
+    }
+
+    // Iterate the allowed providers.
+    foreach ($auth_providers as $provider_id => $provider) {
       if ($provider->applies($request)) {
         // Try to authenticate with this provider, skipping all others.
         $account = $provider->authenticate($request);
diff --git a/core/modules/user/src/Access/LoginStatusCheck.php b/core/modules/user/src/Access/LoginStatusCheck.php
index fbceacd..5bd70aa 100644
--- a/core/modules/user/src/Access/LoginStatusCheck.php
+++ b/core/modules/user/src/Access/LoginStatusCheck.php
@@ -10,6 +10,7 @@
 use Drupal\Core\Routing\Access\AccessInterface;
 use Drupal\Core\Session\AccountInterface;
 use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\Routing\Route;
 
 /**
  * Determines access to routes based on login status of current user.
@@ -19,6 +20,8 @@ class LoginStatusCheck implements AccessInterface {
   /**
    * Checks access.
    *
+   * @param \Symfony\Component\Routing\Route $route
+   *   The route to check against.
    * @param \Symfony\Component\HttpFoundation\Request $request
    *   The request object.
    * @param \Drupal\Core\Session\AccountInterface $account
@@ -27,8 +30,10 @@ class LoginStatusCheck implements AccessInterface {
    * @return string
    *   A \Drupal\Core\Access\AccessInterface constant value.
    */
-  public function access(Request $request, AccountInterface $account) {
-    return ($request->attributes->get('_menu_admin') || $account->isAuthenticated()) ? static::ALLOW : static::DENY;
+  public function access(Route $route, Request $request, AccountInterface $account) {
+    $required_status = filter_var($route->getRequirement('_user_is_logged_in'), FILTER_VALIDATE_BOOLEAN);
+    $actual_status = $account->isAuthenticated();
+    return ($request->attributes->get('_menu_admin') || $required_status == $actual_status) ? static::ALLOW : static::DENY;
   }
 
 }
diff --git a/core/modules/user/src/EventSubscriber/ExceptionRedirectSubscriber.php b/core/modules/user/src/EventSubscriber/ExceptionRedirectSubscriber.php
new file mode 100644
index 0000000..d1c7154
--- /dev/null
+++ b/core/modules/user/src/EventSubscriber/ExceptionRedirectSubscriber.php
@@ -0,0 +1,96 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\user\EventSubscriber\ExceptionRedirectSubscriber.
+ */
+
+namespace Drupal\user\EventSubscriber;
+
+use Drupal\Core\Session\AccountInterface;
+use Drupal\Core\Routing\RouteMatch;
+use Drupal\Core\Routing\UrlGeneratorInterface;
+use Symfony\Component\EventDispatcher\EventSubscriberInterface;
+use Symfony\Component\HttpFoundation\RedirectResponse;
+use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
+use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
+use Symfony\Component\HttpKernel\KernelEvents;
+
+/**
+ * Redirects authenticated users from login/register form to the profile.
+ */
+class ExceptionRedirectSubscriber implements EventSubscriberInterface {
+
+  /**
+   * The current user.
+   *
+   * @var \Drupal\Core\Session\AccountInterface
+   */
+  protected $account;
+
+  /**
+   * The URL generator.
+   *
+   * @var \Drupal\Core\Routing\UrlGeneratorInterface
+   */
+  protected $urlGenerator;
+
+  /**
+   * Constructs a new redirect subscriber.
+   *
+   * @param \Drupal\Core\Session\AccountInterface $account
+   *   The current user.
+   */
+  public function __construct(AccountInterface $account, URLGeneratorInterface $url_generator) {
+    $this->account = $account;
+    $this->urlGenerator = $url_generator;
+  }
+
+  /**
+   * Redirects authenticated users from login/register form to the profile.
+   *
+   * @param \Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent $event
+   *   The event to process.
+   */
+  public function onException(GetResponseForExceptionEvent $event) {
+    $exception = $event->getException();
+    if ($exception instanceof AccessDeniedHttpException && $this->account->isAuthenticated()) {
+      $route_name = RouteMatch::createFromRequest($event->getRequest())->getRouteName();
+      switch ($route_name) {
+        case 'user.login';
+          // If user is logged in, redirect to 'user' instead of giving 403.
+          $event->setResponse(new RedirectResponse($this->url('user.view', array('user' => $this->account->id()), array('absolute' => TRUE))));
+          break;
+
+        case 'user.register';
+          // Authenticated user should be redirected to user edit page.
+          $event->setResponse(new RedirectResponse($this->url('user.edit', array('user' => $this->account->id()), array('absolute' => TRUE))));
+          break;
+      }
+    }
+  }
+
+  /**
+   * Generates a URL or path for a specific route based on the given parameters.
+   *
+   * @see \Drupal\Core\Routing\UrlGeneratorInterface::generateFromRoute() for
+   *   details on the arguments, usage, and possible exceptions.
+   *
+   * @return string
+   *   The generated URL for the given route.
+   *
+   * @todo: Use UrlGeneratorTrait (see https://www.drupal.org/node/2282161)
+   */
+  protected function url($route_name, $route_parameters = array(), $options = array()) {
+    return $this->urlGenerator->generateFromRoute($route_name, $route_parameters, $options);
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function getSubscribedEvents() {
+    $events[KernelEvents::EXCEPTION][] = array('onException');
+    return $events;
+  }
+
+}
diff --git a/core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.php b/core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.php
index 1e8d114..8df86d3 100644
--- a/core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.php
+++ b/core/modules/user/src/EventSubscriber/MaintenanceModeSubscriber.php
@@ -7,6 +7,7 @@
 
 namespace Drupal\user\EventSubscriber;
 
+use Symfony\Cmf\Component\Routing\RouteObjectInterface;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 use Symfony\Component\HttpFoundation\RedirectResponse;
 use Symfony\Component\HttpKernel\Event\GetResponseEvent;
@@ -19,7 +20,7 @@
 class MaintenanceModeSubscriber implements EventSubscriberInterface {
 
   /**
-   * Determine whether the page is configured to be offline.
+   * Logout users if site is in maintenance mode.
    *
    * @param \Symfony\Component\HttpKernel\Event\GetResponseEvent $event
    *   The event to process.
@@ -28,7 +29,7 @@ public function onKernelRequestMaintenance(GetResponseEvent $event) {
     $user = \Drupal::currentUser();
     $request = $event->getRequest();
     $site_status = $request->attributes->get('_maintenance');
-    $path = $request->attributes->get('_system_path');
+    $route_name = $request->attributes->get(RouteObjectInterface::ROUTE_NAME);
     if ($site_status == CoreMaintenanceModeSubscriber::SITE_OFFLINE) {
       // If the site is offline, log out unprivileged users.
       if ($user->isAuthenticated() && !$user->hasPermission('access site in maintenance mode')) {
@@ -39,44 +40,28 @@ public function onKernelRequestMaintenance(GetResponseEvent $event) {
       }
 
       if ($user->isAnonymous()) {
-        switch ($path) {
-          case 'user':
+        switch ($route_name) {
+          case 'user.page':
             // Forward anonymous user to login page.
             $event->setResponse(new RedirectResponse(url('user/login', array('absolute' => TRUE))));
             return;
-          case 'user/login':
-          case 'user/password':
+
+          case 'user.login':
+          case 'user.pass':
+          case 'user.reset':
             // Disable offline mode.
             $request->attributes->set('_maintenance', CoreMaintenanceModeSubscriber::SITE_ONLINE);
             break;
-          default:
-            if (strpos($path, 'user/reset/') === 0) {
-              // Disable offline mode.
-              $request->attributes->set('_maintenance', CoreMaintenanceModeSubscriber::SITE_ONLINE);
-            }
-            break;
         }
       }
     }
-    if ($user->isAuthenticated()) {
-      if ($path == 'user/login') {
-        // If user is logged in, redirect to 'user' instead of giving 403.
-        $event->setResponse(new RedirectResponse(url('user', array('absolute' => TRUE))));
-        return;
-      }
-      if ($path == 'user/register') {
-        // Authenticated user should be redirected to user edit page.
-        $event->setResponse(new RedirectResponse(url('user/' . $user->id() . '/edit', array('absolute' => TRUE))));
-        return;
-      }
-    }
   }
 
   /**
    * {@inheritdoc}
    */
   public static function getSubscribedEvents() {
-    $events[KernelEvents::REQUEST][] = array('onKernelRequestMaintenance', 35);
+    $events[KernelEvents::REQUEST][] = array('onKernelRequestMaintenance', 31);
     return $events;
   }
 
diff --git a/core/modules/user/src/RegisterForm.php b/core/modules/user/src/RegisterForm.php
index ddbbcc0..3e642f9 100644
--- a/core/modules/user/src/RegisterForm.php
+++ b/core/modules/user/src/RegisterForm.php
@@ -40,11 +40,6 @@ public function form(array $form, array &$form_state) {
       '#value' => $admin,
     );
 
-    // If we aren't admin but already logged on, go to the user page instead.
-    if (!$admin && $user->isAuthenticated()) {
-      return new RedirectResponse(url('user/' . \Drupal::currentUser()->id(), array('absolute' => TRUE)));
-    }
-
     $form['#attached']['library'][] = 'core/jquery.cookie';
     $form['#attributes']['class'][] = 'user-info-from-cookie';
 
diff --git a/core/modules/user/user.routing.yml b/core/modules/user/user.routing.yml
index 55c57d1..110bdaf 100644
--- a/core/modules/user/user.routing.yml
+++ b/core/modules/user/user.routing.yml
@@ -145,7 +145,7 @@ user.login:
     _form: '\Drupal\user\Form\UserLoginForm'
     _title: 'Log in'
   requirements:
-    _access: 'TRUE'
+    _user_is_logged_in: 'FALSE'
 
 user.edit:
   path: '/user/{user}/edit'
diff --git a/core/modules/user/user.services.yml b/core/modules/user/user.services.yml
index 1e8f9b3..52d9234 100644
--- a/core/modules/user/user.services.yml
+++ b/core/modules/user/user.services.yml
@@ -40,6 +40,11 @@ services:
     class: Drupal\user\EventSubscriber\MaintenanceModeSubscriber
     tags:
       - { name: event_subscriber }
+  user_exception_redirect_subscriber:
+    class: Drupal\user\EventSubscriber\ExceptionRedirectSubscriber
+    arguments: ['@current_user', '@url_generator']
+    tags:
+      - { name: event_subscriber }
   theme.negotiator.admin_theme:
     class: Drupal\user\Theme\AdminNegotiator
     arguments: ['@current_user', '@config.factory', '@entity.manager', '@router.admin_context']
