aspnetcore/src/MvcMusicStore/Controllers/AccountController.cs

421 lines
13 KiB
C#

using System.Collections.Generic;
using System.Security.Claims;
using System.Threading.Tasks;
using System.Web;
using System.Web.Mvc;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
using Microsoft.Owin.Security;
using MvcMusicStore.Models;
namespace MvcMusicStore.Controllers
{
[Authorize]
public class AccountController : Controller
{
public enum ManageMessageId
{
ChangePasswordSuccess,
SetPasswordSuccess,
RemoveLoginSuccess,
Error
}
private const string XsrfKey = "XsrfId";
private UserManager<ApplicationUser> _userManager;
public AccountController()
: this(new UserManager<ApplicationUser>(new UserStore<ApplicationUser>(new ApplicationDbContext())))
{
}
public AccountController(UserManager<ApplicationUser> userManager)
{
_userManager = userManager;
}
private IAuthenticationManager AuthenticationManager
{
get { return HttpContext.GetOwinContext().Authentication; }
}
private async Task MigrateShoppingCart(string userName)
{
using (var storeContext = new MusicStoreEntities())
{
var cart = ShoppingCart.GetCart(storeContext, this);
await cart.MigrateCart(userName);
Session[ShoppingCart.CartSessionKey] = userName;
}
}
// GET: /Account/Login
[AllowAnonymous]
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
// POST: /Account/Login
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
{
var user = await _userManager.FindAsync(model.UserName, model.Password);
if (user != null)
{
await SignInAsync(user, model.RememberMe);
return RedirectToLocal(returnUrl);
}
ModelState.AddModelError("", "Invalid username or password.");
}
return View(model);
}
// GET: /Account/Register
[AllowAnonymous]
public ActionResult Register()
{
return View();
}
// POST: /Account/Register
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
{
var user = new ApplicationUser { UserName = model.UserName };
var result = await _userManager.CreateAsync(user, model.Password);
if (result.Succeeded)
{
await SignInAsync(user, false);
return RedirectToAction("Index", "Home");
}
AddErrors(result);
}
return View(model);
}
// POST: /Account/Disassociate
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Disassociate(string loginProvider, string providerKey)
{
var result = await _userManager.RemoveLoginAsync(
User.Identity.GetUserId(),
new UserLoginInfo(loginProvider, providerKey));
return RedirectToAction(
"Manage",
new { Message = result.Succeeded ? ManageMessageId.RemoveLoginSuccess : ManageMessageId.Error });
}
// GET: /Account/Manage
public async Task<ActionResult> Manage(ManageMessageId? message)
{
switch (message)
{
case ManageMessageId.ChangePasswordSuccess:
ViewBag.StatusMessage = "Your password has been changed.";
break;
case ManageMessageId.SetPasswordSuccess:
ViewBag.StatusMessage = "Your password has been set.";
break;
case ManageMessageId.RemoveLoginSuccess:
ViewBag.StatusMessage = "The external login was removed.";
break;
case ManageMessageId.Error:
ViewBag.StatusMessage = "An error has occurred.";
break;
default:
ViewBag.StatusMessage = "";
break;
}
ViewBag.HasLocalPassword = await HasPasswordAsync();
ViewBag.ReturnUrl = Url.Action("Manage");
return View();
}
// POST: /Account/Manage
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Manage(ManageUserViewModel model)
{
bool hasPassword = await HasPasswordAsync();
ViewBag.HasLocalPassword = hasPassword;
ViewBag.ReturnUrl = Url.Action("Manage");
if (hasPassword)
{
if (ModelState.IsValid)
{
var result = await _userManager.ChangePasswordAsync(
User.Identity.GetUserId(),
model.OldPassword,
model.NewPassword);
if (result.Succeeded)
{
return RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess });
}
AddErrors(result);
}
}
else
{
var state = ModelState["OldPassword"];
if (state != null)
{
state.Errors.Clear();
}
if (ModelState.IsValid)
{
var result = await _userManager.AddPasswordAsync(
User.Identity.GetUserId(),
model.NewPassword);
if (result.Succeeded)
{
return RedirectToAction("Manage", new { Message = ManageMessageId.SetPasswordSuccess });
}
AddErrors(result);
}
}
return View(model);
}
// POST: /Account/ExternalLogin
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public ActionResult ExternalLogin(string provider, string returnUrl)
{
return new ChallengeResult(provider,
Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
}
// GET: /Account/ExternalLoginCallback
[AllowAnonymous]
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
return RedirectToAction("Login");
}
var user = await _userManager.FindAsync(loginInfo.Login);
if (user != null)
{
await SignInAsync(user, false);
return RedirectToLocal(returnUrl);
}
ViewBag.ReturnUrl = returnUrl;
ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
return View("ExternalLoginConfirmation",
new ExternalLoginConfirmationViewModel { UserName = loginInfo.DefaultUserName });
}
// POST: /Account/LinkLogin
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LinkLogin(string provider)
{
return new ChallengeResult(provider, Url.Action("LinkLoginCallback", "Account"), User.Identity.GetUserId());
}
// GET: /Account/LinkLoginCallback
public async Task<ActionResult> LinkLoginCallback()
{
var loginInfo =
await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId());
if (loginInfo == null)
{
return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
}
var result = await _userManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login);
if (result.Succeeded)
{
return RedirectToAction("Manage");
}
return RedirectToAction("Manage", new { Message = ManageMessageId.Error });
}
// POST: /Account/ExternalLoginConfirmation
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> ExternalLoginConfirmation(
ExternalLoginConfirmationViewModel model,
string returnUrl)
{
if (User.Identity.IsAuthenticated)
{
return RedirectToAction("Manage");
}
if (ModelState.IsValid)
{
// Get the information about the user from the external login provider
var info = await AuthenticationManager.GetExternalLoginInfoAsync();
if (info == null)
{
return View("ExternalLoginFailure");
}
var user = new ApplicationUser { UserName = model.UserName };
var result = await _userManager.CreateAsync(user);
if (result.Succeeded)
{
result = await _userManager.AddLoginAsync(user.Id, info.Login);
if (result.Succeeded)
{
await SignInAsync(user, false);
return RedirectToLocal(returnUrl);
}
}
AddErrors(result);
}
ViewBag.ReturnUrl = returnUrl;
return View(model);
}
// POST: /Account/LogOff
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LogOff()
{
AuthenticationManager.SignOut();
return RedirectToAction("Index", "Home");
}
// GET: /Account/ExternalLoginFailure
[AllowAnonymous]
public ActionResult ExternalLoginFailure()
{
return View();
}
[ChildActionOnly]
public ActionResult RemoveAccountList()
{
var linkedAccounts = _userManager.GetLogins(User.Identity.GetUserId());
ViewBag.ShowRemoveButton = HasPassword() || linkedAccounts.Count > 1;
return PartialView("_RemoveAccountPartial", linkedAccounts);
}
protected override void Dispose(bool disposing)
{
if (disposing && _userManager != null)
{
_userManager.Dispose();
_userManager = null;
}
base.Dispose(disposing);
}
private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity =
await _userManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
AuthenticationManager.SignIn(new AuthenticationProperties { IsPersistent = isPersistent }, identity);
await MigrateShoppingCart(user.UserName);
}
private void AddErrors(IdentityResult result)
{
foreach (var error in result.Errors)
{
ModelState.AddModelError("", error);
}
}
private bool HasPassword()
{
var user = _userManager.FindById(User.Identity.GetUserId());
return user != null && user.PasswordHash != null;
}
private async Task<bool> HasPasswordAsync()
{
var user = await _userManager.FindByIdAsync(User.Identity.GetUserId());
return user != null && user.PasswordHash != null;
}
private ActionResult RedirectToLocal(string returnUrl)
{
return Url.IsLocalUrl(returnUrl)
? (ActionResult)Redirect(returnUrl)
: RedirectToAction("Index", "Home");
}
private class ChallengeResult : HttpUnauthorizedResult
{
private readonly string _loginProvider;
private readonly string _redirectUri;
private readonly string _userId;
public ChallengeResult(string provider, string redirectUri, string userId = null)
{
_loginProvider = provider;
_redirectUri = redirectUri;
_userId = userId;
}
public override void ExecuteResult(ControllerContext context)
{
var properties = new AuthenticationProperties { RedirectUri = _redirectUri };
if (_userId != null)
{
properties.Dictionary[XsrfKey] = _userId;
}
context.HttpContext.GetOwinContext().Authentication.Challenge(properties, _loginProvider);
}
}
}
}