title: MVC only alow admin login
body: <p>I am working on a MVC5 EF6 database in Visual Studio 2013. The database is using Individual User Accounts for authentication with user roles.</p>
  
  <p>In IIS it is possible to get the entire site down (e.g. for maintenance) by putting the <code>app_offline.htm</code> file. After I have updated the site and maybe migrated the database, as administrator I would like to perform some tests on the production machine before allowing all other users to login.</p>
  
  <p>Is there a simple way to lockout all users except administrator from logging in until the administrator allows them to login ?</p>
  
  <p>It would be nice if a similar construction can be used as the <code>app_offline.htm</code> file. </p>
  
  <p>Below the code of the login method. </p>
  
  <pre><code>[HttpPost]
  [AllowAnonymous]
  [ValidateAntiForgeryToken]
  public async Task&lt;ActionResult&gt; Login(LoginViewModel model, string returnUrl)
  {
      if (!ModelState.IsValid)
      {
          return View(model);
      }
  
      // This doesn't count login failures towards account lockout
      // To enable password failures to trigger account lockout, change to shouldLockout: true
      var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: true);
      switch (result)
      {
          case SignInStatus.Success:
              return RedirectToLocal(returnUrl);
          case SignInStatus.LockedOut:
              return View("Lockout");
          case SignInStatus.RequiresVerification:
              return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = model.RememberMe });
          case SignInStatus.Failure:
          default:
              ModelState.AddModelError("", "Invalid login attempt.");
              return View(model);
      }
  }
  </code></pre>
  
  <p>I can imagine it would be possible to add some code in case <code>Success</code> to logout the user (if not memeber of administrators) and redirect to a special "logins temporary disabled" page. However, there might be better (or builtin) alternatives.</p>
  
  <p><strong>Edit:</strong> </p>
  
  <p>I tried the filtes and they do not work as I expected. However, I will keep filters in mind to test with if I have some more time to do so.</p>
  
  <p>For now I use the following code in the login method</p>
  
  <pre><code>if (!ModelState.IsValid)
  {
      return View(model);
  }
  
  ApplicationUser au = UserManager.FindByName(model.UserName);
  
  // If user is found and not member of administrators
  if (au != null &amp;&amp; !UserManager.IsInRole(au.Id, "Administrator"))
  {
      // Check if the adminmode file exisits in the root. If so, redirect to it
      String adminModeFilePath = System.IO.Path.Combine(HttpRuntime.AppDomainAppPath, "app_adminmode.htm");
      if (System.IO.File.Exists(adminModeFilePath))
      {
          return new FilePathResult(adminModeFilePath, MediaTypeNames.Text.Html);
      }
  }
  
  // This doesn't count login failures towards account lockout
  // To enable password failures to trigger account lockout, change to shouldLockout: true
  var result = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: true);
  </code></pre>
  
  <p>For <code>"Administrator"</code> and <code>"app_adminmode.htm"</code> I actually use constants which are declared in a central place, but for SO completeness I use the string here. If the user trying to login exists and is not in role Administrator, I will check the file. If the file exists the user is not logged in, but redirected</p>