Merge pull request #268 from dotnet-architecture/remove-account-controller

Remove account controller
This commit is contained in:
Eric Fleming
2019-06-22 16:03:30 -04:00
committed by GitHub
5 changed files with 61 additions and 247 deletions

View File

@@ -0,0 +1,12 @@
@page
@model ConfirmEmailModel
@{
ViewData["Title"] = "Confirm email";
}
<h2>@ViewData["Title"]</h2>
<div>
<p>
Thank you for confirming your email.
</p>
</div>

View File

@@ -0,0 +1,45 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
using Microsoft.eShopWeb.Infrastructure.Identity;
namespace Microsoft.eShopWeb.Web.Areas.Identity.Pages.Account
{
[AllowAnonymous]
public class ConfirmEmailModel : PageModel
{
private readonly UserManager<ApplicationUser> _userManager;
public ConfirmEmailModel(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
public async Task<IActionResult> OnGetAsync(string userId, string code)
{
if (userId == null || code == null)
{
return RedirectToPage("/Index");
}
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
return NotFound($"Unable to load user with ID '{userId}'.");
}
var result = await _userManager.ConfirmEmailAsync(user, code);
if (!result.Succeeded)
{
throw new InvalidOperationException($"Error confirming email for user with ID '{userId}':");
}
return Page();
}
}
}

View File

@@ -1,232 +0,0 @@
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.eShopWeb.ApplicationCore.Interfaces;
using Microsoft.eShopWeb.Infrastructure.Identity;
using Microsoft.eShopWeb.Web.ViewModels.Account;
using System;
using System.Threading.Tasks;
namespace Microsoft.eShopWeb.Web.Controllers
{
[ApiExplorerSettings(IgnoreApi = true)]
[Route("[controller]/[action]")]
[Authorize] // Controllers that mainly require Authorization still use Controller/View; other pages use Pages
public class AccountController : Controller
{
private readonly UserManager<ApplicationUser> _userManager;
private readonly SignInManager<ApplicationUser> _signInManager;
private readonly IBasketService _basketService;
private readonly IAppLogger<AccountController> _logger;
public AccountController(
UserManager<ApplicationUser> userManager,
SignInManager<ApplicationUser> signInManager,
IBasketService basketService,
IAppLogger<AccountController> logger)
{
_userManager = userManager;
_signInManager = signInManager;
_basketService = basketService;
_logger = logger;
}
// GET: /Account/SignIn
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> SignIn(string returnUrl = null)
{
await HttpContext.SignOutAsync(IdentityConstants.ExternalScheme);
ViewData["ReturnUrl"] = returnUrl;
if (!String.IsNullOrEmpty(returnUrl) &&
returnUrl.IndexOf("checkout", StringComparison.OrdinalIgnoreCase) >= 0)
{
ViewData["ReturnUrl"] = "/Basket/Index";
}
return View();
}
// POST: /Account/SignIn
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> SignIn(LoginViewModel model, string returnUrl = null)
{
if (!ModelState.IsValid)
{
return View(model);
}
ViewData["ReturnUrl"] = returnUrl;
var result = await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, lockoutOnFailure: false);
if (result.RequiresTwoFactor)
{
return RedirectToAction(nameof(LoginWith2fa), new { returnUrl, model.RememberMe });
}
if (result.Succeeded)
{
string anonymousBasketId = Request.Cookies[Constants.BASKET_COOKIENAME];
if (!String.IsNullOrEmpty(anonymousBasketId))
{
await _basketService.TransferBasketAsync(anonymousBasketId, model.Email);
Response.Cookies.Delete(Constants.BASKET_COOKIENAME);
}
return RedirectToLocal(returnUrl);
}
ModelState.AddModelError(string.Empty, "Invalid login attempt.");
return View(model);
}
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> LoginWith2fa(bool rememberMe, string returnUrl = null)
{
// Ensure the user has gone through the username & password screen first
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
if (user == null)
{
throw new ApplicationException($"Unable to load two-factor authentication user.");
}
var model = new LoginWith2faViewModel { RememberMe = rememberMe };
ViewData["ReturnUrl"] = returnUrl;
return View(model);
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> LoginWith2fa(LoginWith2faViewModel model, bool rememberMe, string returnUrl = null)
{
if (!ModelState.IsValid)
{
return View(model);
}
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
if (user == null)
{
throw new ApplicationException($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
}
var authenticatorCode = model.TwoFactorCode.Replace(" ", string.Empty).Replace("-", string.Empty);
var result = await _signInManager.TwoFactorAuthenticatorSignInAsync(authenticatorCode, rememberMe, model.RememberMachine);
if (result.Succeeded)
{
_logger.LogInformation("User with ID {UserId} logged in with 2fa.", user.Id);
return RedirectToLocal(returnUrl);
}
else if (result.IsLockedOut)
{
_logger.LogWarning("User with ID {UserId} account locked out.", user.Id);
return RedirectToAction(nameof(Lockout));
}
else
{
_logger.LogWarning("Invalid authenticator code entered for user with ID {UserId}.", user.Id);
ModelState.AddModelError(string.Empty, "Invalid authenticator code.");
return View();
}
}
[HttpGet]
[AllowAnonymous]
public IActionResult Lockout()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> SignOut()
{
await _signInManager.SignOutAsync();
return RedirectToPage("/Index");
}
[AllowAnonymous]
[HttpGet]
public IActionResult Register()
{
return View();
}
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Register(RegisterViewModel model, string returnUrl = null)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await _signInManager.SignInAsync(user, isPersistent: false);
return RedirectToLocal(returnUrl);
}
AddErrors(result);
}
// If we got this far, something failed, redisplay form
return View(model);
}
[HttpGet]
[AllowAnonymous]
public async Task<IActionResult> ConfirmEmail(string userId, string code)
{
if (userId == null || code == null)
{
return RedirectToPage("/Index");
}
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
throw new ApplicationException($"Unable to load user with ID '{userId}'.");
}
var result = await _userManager.ConfirmEmailAsync(user, code);
return View(result.Succeeded ? "ConfirmEmail" : "Error");
}
[HttpGet]
[AllowAnonymous]
public IActionResult ResetPassword(string code = null)
{
if (code == null)
{
throw new ApplicationException("A code must be supplied for password reset.");
}
var model = new ResetPasswordViewModel { Code = code };
return View(model);
}
private IActionResult RedirectToLocal(string returnUrl)
{
if (Url.IsLocalUrl(returnUrl))
{
return Redirect(returnUrl);
}
else
{
return RedirectToPage("/Index");
}
}
private void AddErrors(IdentityResult result)
{
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error.Description);
}
}
}
}

View File

@@ -1,23 +1,12 @@
using Microsoft.eShopWeb.Web.Controllers;
namespace Microsoft.AspNetCore.Mvc
namespace Microsoft.AspNetCore.Mvc
{
public static class UrlHelperExtensions
{
public static string EmailConfirmationLink(this IUrlHelper urlHelper, string userId, string code, string scheme)
{
return urlHelper.Action(
action: nameof(AccountController.ConfirmEmail),
controller: "Account",
values: new { userId, code },
protocol: scheme);
}
public static string ResetPasswordCallbackLink(this IUrlHelper urlHelper, string userId, string code, string scheme)
{
return urlHelper.Action(
action: nameof(AccountController.ResetPassword),
controller: "Account",
action: "GET",
controller: "ConfirmEmail",
values: new { userId, code },
protocol: scheme);
}

View File

@@ -81,7 +81,7 @@ namespace Microsoft.eShopWeb.FunctionalTests.Web.Controllers
keyValues.Add(new KeyValuePair<string, string>("__RequestVerificationToken", token));
var formContent = new FormUrlEncodedContent(keyValues);
var postResponse = await Client.PostAsync("/account/sign-in", formContent);
var postResponse = await Client.PostAsync("/identity/account/login", formContent);
Assert.Equal(HttpStatusCode.Redirect, postResponse.StatusCode);
Assert.Equal(new System.Uri("/", UriKind.Relative), postResponse.Headers.Location);
}