421 lines
13 KiB
C#
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);
|
|
}
|
|
}
|
|
}
|
|
} |