Updating the sample to use VS 2013 Update 3 templates for Identity
1. This contains the new manage controller with a bunch of features like 2 factor auth Some of the features are not enabled yet. But this is to set a baseline with update3 templates. Automation to come up in future as more identity extensions are available.
This commit is contained in:
parent
05cd84667a
commit
9f4d46714b
|
|
@ -1,8 +1,11 @@
|
|||
using Microsoft.AspNet.Identity;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using MusicStore.Models;
|
||||
using System.Linq;
|
||||
using System.Security.Principal;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNet.Http.Security;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using MusicStore.Models;
|
||||
|
||||
namespace MusicStore.Controllers
|
||||
{
|
||||
|
|
@ -35,25 +38,78 @@ namespace MusicStore.Controllers
|
|||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Login(LoginViewModel model, string returnUrl = null)
|
||||
{
|
||||
if (ModelState.IsValid)
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
var signInStatus = await SignInManager.PasswordSignInAsync(model.UserName, model.Password, model.RememberMe, shouldLockout: false);
|
||||
switch (signInStatus)
|
||||
{
|
||||
case SignInStatus.Success:
|
||||
return RedirectToLocal(returnUrl);
|
||||
case SignInStatus.LockedOut:
|
||||
ModelState.AddModelError("", "User is locked out, try again later.");
|
||||
return View(model);
|
||||
case SignInStatus.Failure:
|
||||
default:
|
||||
ModelState.AddModelError("", "Invalid username or password.");
|
||||
return View(model);
|
||||
}
|
||||
return View(model);
|
||||
}
|
||||
|
||||
// If we got this far, something failed, redisplay form
|
||||
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 signInStatus = await SignInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, shouldLockout: false);
|
||||
switch (signInStatus)
|
||||
{
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/VerifyCode
|
||||
//TODO : Some of the identity helpers not implemented
|
||||
//[AllowAnonymous]
|
||||
//public async Task<ActionResult> VerifyCode(string provider, string returnUrl, bool rememberMe)
|
||||
//{
|
||||
// // Require that the user has already logged in via username/password or external login
|
||||
// if (!await SignInManager.HasBeenVerifiedAsync())
|
||||
// {
|
||||
// return View("Error");
|
||||
// }
|
||||
// var user = await UserManager.FindByIdAsync(await SignInManager.GetVerifiedUserIdAsync());
|
||||
// if (user != null)
|
||||
// {
|
||||
// var code = await UserManager.GenerateTwoFactorTokenAsync(user.Id, provider);
|
||||
// }
|
||||
// return View(new VerifyCodeViewModel { Provider = provider, ReturnUrl = returnUrl, RememberMe = rememberMe });
|
||||
//}
|
||||
|
||||
//
|
||||
// POST: /Account/VerifyCode
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<ActionResult> VerifyCode(VerifyCodeViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
|
||||
// The following code protects for brute force attacks against the two factor codes.
|
||||
// If a user enters incorrect codes for a specified amount of time then the user account
|
||||
// will be locked out for a specified amount of time.
|
||||
// You can configure the account lockout settings in IdentityConfig
|
||||
// TODO : This helper does not take in the remember browser option yet.
|
||||
// var result = await SignInManager.TwoFactorSignInAsync(model.Provider, model.Code, isPersistent: model.RememberMe, rememberBrowser: model.RememberBrowser);
|
||||
var result = await SignInManager.TwoFactorSignInAsync(model.Provider, model.Code, isPersistent: model.RememberMe);
|
||||
switch (result)
|
||||
{
|
||||
case SignInStatus.Success:
|
||||
return RedirectToLocal(model.ReturnUrl);
|
||||
case SignInStatus.LockedOut:
|
||||
return View("Lockout");
|
||||
case SignInStatus.Failure:
|
||||
default:
|
||||
ModelState.AddModelError("", "Invalid code.");
|
||||
return View(model);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
|
|
@ -73,17 +129,26 @@ namespace MusicStore.Controllers
|
|||
{
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var user = new ApplicationUser { UserName = model.UserName };
|
||||
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
|
||||
var result = await UserManager.CreateAsync(user, model.Password);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
//Bug: Remember browser option missing?
|
||||
await SignInManager.SignInAsync(user, isPersistent: false);
|
||||
|
||||
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
|
||||
// Send an email with this link
|
||||
//string code = await UserManager.GenerateEmailConfirmationTokenAsync(user);
|
||||
//var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: Context.Request.Scheme);
|
||||
// await UserManager.SendEmailAsync(user.Id, "Confirm your account", "Please confirm your account by clicking <a href=\"" + callbackUrl + "\">here</a>");
|
||||
// return RedirectToAction("Index", "Home");
|
||||
|
||||
// TODO: Email libraries not available on Coreclr yet - Checkout a demo implementation below which displays the code in the browser for testing.
|
||||
//ViewBag.Status = "Navigate to this URL to confirm your account " + callbackUrl;
|
||||
//return View("DemoCodeDisplay");
|
||||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
else
|
||||
{
|
||||
AddErrors(result);
|
||||
}
|
||||
AddErrors(result);
|
||||
}
|
||||
|
||||
// If we got this far, something failed, redisplay form
|
||||
|
|
@ -91,42 +156,234 @@ namespace MusicStore.Controllers
|
|||
}
|
||||
|
||||
//
|
||||
// GET: /Account/Manage
|
||||
public IActionResult Manage(ManageMessageId? message = null)
|
||||
// GET: /Account/ConfirmEmail
|
||||
//TODO: This does not work yet due to some missing identity features
|
||||
[AllowAnonymous]
|
||||
public async Task<ActionResult> ConfirmEmail(string userId, string code)
|
||||
{
|
||||
if (userId == null || code == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var user = new ApplicationUser { Id = userId };
|
||||
//Bug: Throws NullRefException
|
||||
var result = await UserManager.ConfirmEmailAsync(user, code);
|
||||
return View(result.Succeeded ? "ConfirmEmail" : "Error");
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/ForgotPassword
|
||||
[AllowAnonymous]
|
||||
public ActionResult ForgotPassword()
|
||||
{
|
||||
ViewBag.StatusMessage =
|
||||
message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
|
||||
: message == ManageMessageId.Error ? "An error has occurred."
|
||||
: "";
|
||||
ViewBag.ReturnUrl = Url.Action("Manage");
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/Manage
|
||||
// POST: /Account/ForgotPassword
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> Manage(ManageUserViewModel model)
|
||||
public async Task<ActionResult> ForgotPassword(ForgotPasswordViewModel model)
|
||||
{
|
||||
ViewBag.ReturnUrl = Url.Action("Manage");
|
||||
if (ModelState.IsValid)
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
var result = await UserManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword);
|
||||
if (result.Succeeded)
|
||||
var user = await UserManager.FindByNameAsync(model.Email);
|
||||
if (user == null || !(await UserManager.IsEmailConfirmedAsync(user)))
|
||||
{
|
||||
return RedirectToAction("Manage", new { Message = ManageMessageId.ChangePasswordSuccess });
|
||||
}
|
||||
else
|
||||
{
|
||||
AddErrors(result);
|
||||
// Don't reveal that the user does not exist or is not confirmed
|
||||
return View("ForgotPasswordConfirmation");
|
||||
}
|
||||
|
||||
// For more information on how to enable account confirmation and password reset please visit http://go.microsoft.com/fwlink/?LinkID=320771
|
||||
// Send an email with this link
|
||||
string code = await UserManager.GeneratePasswordResetTokenAsync(user);
|
||||
var callbackUrl = Url.Action("ResetPassword", "Account", new { code = code }, protocol: Context.Request.Scheme);
|
||||
// No libraries to send email on CoreCLR yet
|
||||
// await UserManager.SendEmailAsync(user.Id, "Reset Password", "Please reset your password by clicking <a href=\"" + callbackUrl + "\">here</a>");
|
||||
// return RedirectToAction("ForgotPasswordConfirmation", "Account");
|
||||
|
||||
// TODO: Email libraries not available on Coreclr yet - Checkout a demo implementation below which displays the code in the browser for testing.
|
||||
ViewBag.Status = "Navigate to the URL to reset password " + callbackUrl;
|
||||
return View("DemoCodeDisplay");
|
||||
}
|
||||
|
||||
ModelState.AddModelError("", string.Format("We could not locate an account with email : {0}", model.Email));
|
||||
|
||||
// If we got this far, something failed, redisplay form
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/ForgotPasswordConfirmation
|
||||
[AllowAnonymous]
|
||||
public ActionResult ForgotPasswordConfirmation()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/ResetPassword
|
||||
[AllowAnonymous]
|
||||
public ActionResult ResetPassword(string code)
|
||||
{
|
||||
var resetPasswordViewModel = new ResetPasswordViewModel() { Code = code };
|
||||
return code == null ? View("Error") : View(resetPasswordViewModel);
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/ResetPassword
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<ActionResult> ResetPassword(ResetPasswordViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
var user = await UserManager.FindByNameAsync(model.Email);
|
||||
if (user == null)
|
||||
{
|
||||
// Don't reveal that the user does not exist
|
||||
return RedirectToAction("ResetPasswordConfirmation", "Account");
|
||||
}
|
||||
var result = await UserManager.ResetPasswordAsync(user, model.Code, model.Password);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
return RedirectToAction("ResetPasswordConfirmation", "Account");
|
||||
}
|
||||
AddErrors(result);
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/ResetPasswordConfirmation
|
||||
[AllowAnonymous]
|
||||
public ActionResult ResetPasswordConfirmation()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/ExternalLogin
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[ValidateAntiForgeryToken]
|
||||
public ActionResult ExternalLogin(string provider, string returnUrl)
|
||||
{
|
||||
// Request a redirect to the external login provider
|
||||
var redirectUri = Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl });
|
||||
return new ChallengeResult(provider, new AuthenticationProperties() { RedirectUri = redirectUri });
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/SendCode
|
||||
[AllowAnonymous]
|
||||
public async Task<ActionResult> SendCode(bool rememberMe, string returnUrl = null)
|
||||
{
|
||||
// TODO: This currently throws
|
||||
var userId = await GetCurrentUserAsync();
|
||||
if (userId == null)
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
var userFactors = await UserManager.GetValidTwoFactorProvidersAsync(userId);
|
||||
var factorOptions = userFactors.Select(purpose => new SelectListItem { Text = purpose, Value = purpose }).ToList();
|
||||
return View(new SendCodeViewModel { Providers = factorOptions, ReturnUrl = returnUrl, RememberMe = rememberMe });
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/SendCode
|
||||
[HttpPost]
|
||||
[AllowAnonymous]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<ActionResult> SendCode(SendCodeViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
// Generate the token and send it
|
||||
if (!await SignInManager.SendTwoFactorCodeAsync(model.SelectedProvider))
|
||||
{
|
||||
return View("Error");
|
||||
}
|
||||
return RedirectToAction("VerifyCode", new { Provider = model.SelectedProvider, ReturnUrl = model.ReturnUrl, RememberMe = model.RememberMe });
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/ExternalLoginCallback
|
||||
// TODO: Some identity helpers on external login does not exist
|
||||
//[AllowAnonymous]
|
||||
//public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
|
||||
//{
|
||||
// var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
|
||||
// if (loginInfo == null)
|
||||
// {
|
||||
// return RedirectToAction("Login");
|
||||
// }
|
||||
|
||||
// // Sign in the user with this external login provider if the user already has a login
|
||||
// var result = await SignInManager.ExternalSignInAsync(loginInfo, isPersistent: false);
|
||||
// switch (result)
|
||||
// {
|
||||
// case SignInStatus.Success:
|
||||
// return RedirectToLocal(returnUrl);
|
||||
// case SignInStatus.LockedOut:
|
||||
// return View("Lockout");
|
||||
// case SignInStatus.RequiresVerification:
|
||||
// return RedirectToAction("SendCode", new { ReturnUrl = returnUrl, RememberMe = false });
|
||||
// case SignInStatus.Failure:
|
||||
// default:
|
||||
// // If the user does not have an account, then prompt the user to create an account
|
||||
// ViewBag.ReturnUrl = returnUrl;
|
||||
// ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
|
||||
// return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email });
|
||||
// }
|
||||
//}
|
||||
|
||||
//
|
||||
// POST: /Account/ExternalLoginConfirmation
|
||||
// TODO: Some of the identity helpers not available
|
||||
//[HttpPost]
|
||||
//[AllowAnonymous]
|
||||
//[ValidateAntiForgeryToken]
|
||||
//public async Task<ActionResult> ExternalLoginConfirmation(ExternalLoginConfirmationViewModel model, string returnUrl)
|
||||
//{
|
||||
// if (User.Identity.IsAuthenticated)
|
||||
// {
|
||||
// return RedirectToAction("Index", "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.Email, Email = model.Email };
|
||||
// var result = await UserManager.CreateAsync(user);
|
||||
// if (result.Succeeded)
|
||||
// {
|
||||
// result = await UserManager.AddLoginAsync(user.Id, info.Login);
|
||||
// if (result.Succeeded)
|
||||
// {
|
||||
// // TODO: rememberBrowser option not being taken in SignInAsync
|
||||
// await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
|
||||
// return RedirectToLocal(returnUrl);
|
||||
// }
|
||||
// }
|
||||
// AddErrors(result);
|
||||
// }
|
||||
|
||||
// ViewBag.ReturnUrl = returnUrl;
|
||||
// return View(model);
|
||||
//}
|
||||
|
||||
//
|
||||
// POST: /Account/LogOff
|
||||
[HttpPost]
|
||||
|
|
@ -137,6 +394,14 @@ namespace MusicStore.Controllers
|
|||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/ExternalLoginFailure
|
||||
[AllowAnonymous]
|
||||
public ActionResult ExternalLoginFailure()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
#region Helpers
|
||||
|
||||
private void AddErrors(IdentityResult result)
|
||||
|
|
@ -152,13 +417,7 @@ namespace MusicStore.Controllers
|
|||
return await UserManager.FindByIdAsync(Context.User.Identity.GetUserId());
|
||||
}
|
||||
|
||||
public enum ManageMessageId
|
||||
{
|
||||
ChangePasswordSuccess,
|
||||
Error
|
||||
}
|
||||
|
||||
private IActionResult RedirectToLocal(string returnUrl)
|
||||
private ActionResult RedirectToLocal(string returnUrl)
|
||||
{
|
||||
if (Url.IsLocalUrl(returnUrl))
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,348 @@
|
|||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Security.Principal;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Microsoft.AspNet.Mvc;
|
||||
using MusicStore.Models;
|
||||
|
||||
namespace MusicStore.Controllers
|
||||
{
|
||||
/// <summary>
|
||||
/// Summary description for ManageController
|
||||
/// </summary>
|
||||
public class ManageController : Controller
|
||||
{
|
||||
public ManageController(UserManager<ApplicationUser> userManager, SignInManager<ApplicationUser> signInManager)
|
||||
{
|
||||
UserManager = userManager;
|
||||
SignInManager = signInManager;
|
||||
}
|
||||
|
||||
public UserManager<ApplicationUser> UserManager { get; private set; }
|
||||
|
||||
public SignInManager<ApplicationUser> SignInManager { get; private set; }
|
||||
|
||||
//
|
||||
// GET: /Manage/Index
|
||||
public async Task<ActionResult> Index(ManageMessageId? message = null)
|
||||
{
|
||||
ViewBag.StatusMessage =
|
||||
message == ManageMessageId.ChangePasswordSuccess ? "Your password has been changed."
|
||||
: message == ManageMessageId.SetPasswordSuccess ? "Your password has been set."
|
||||
: message == ManageMessageId.SetTwoFactorSuccess ? "Your two-factor authentication provider has been set."
|
||||
: message == ManageMessageId.Error ? "An error has occurred."
|
||||
: message == ManageMessageId.AddPhoneSuccess ? "Your phone number was added."
|
||||
: message == ManageMessageId.RemovePhoneSuccess ? "Your phone number was removed."
|
||||
: "";
|
||||
|
||||
var user = await GetCurrentUserAsync();
|
||||
var model = new IndexViewModel
|
||||
{
|
||||
HasPassword = await UserManager.HasPasswordAsync(user),
|
||||
PhoneNumber = await UserManager.GetPhoneNumberAsync(user),
|
||||
TwoFactor = await UserManager.GetTwoFactorEnabledAsync(user),
|
||||
Logins = await UserManager.GetLoginsAsync(user),
|
||||
BrowserRemembered = await SignInManager.IsTwoFactorClientRememberedAsync(user)
|
||||
};
|
||||
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/RemoveLogin
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> RemoveLogin(string loginProvider, string providerKey)
|
||||
{
|
||||
ManageMessageId? message = ManageMessageId.Error;
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var result = await UserManager.RemoveLoginAsync(user, loginProvider, providerKey);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await SignInManager.SignInAsync(user, isPersistent: false);
|
||||
message = ManageMessageId.RemoveLoginSuccess;
|
||||
}
|
||||
}
|
||||
return RedirectToAction("ManageLogins", new { Message = message });
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/AddPhoneNumber
|
||||
public IActionResult AddPhoneNumber()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/AddPhoneNumber
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> AddPhoneNumber(AddPhoneNumberViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
// Generate the token and send it
|
||||
var code = await UserManager.GenerateChangePhoneNumberTokenAsync(await GetCurrentUserAsync(), model.Number);
|
||||
if (UserManager.SmsService != null)
|
||||
{
|
||||
var message = new IdentityMessage
|
||||
{
|
||||
Destination = model.Number,
|
||||
Body = "Your security code is: " + code
|
||||
};
|
||||
await UserManager.SmsService.SendAsync(message);
|
||||
}
|
||||
|
||||
return RedirectToAction("VerifyPhoneNumber", new { PhoneNumber = model.Number });
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/EnableTwoFactorAuthentication
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> EnableTwoFactorAuthentication()
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
await UserManager.SetTwoFactorEnabledAsync(user, true);
|
||||
// TODO: flow remember me somehow?
|
||||
await SignInManager.SignInAsync(user, isPersistent: false);
|
||||
}
|
||||
return RedirectToAction("Index", "Manage");
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/DisableTwoFactorAuthentication
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> DisableTwoFactorAuthentication()
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
await UserManager.SetTwoFactorEnabledAsync(user, false);
|
||||
await SignInManager.SignInAsync(user, isPersistent: false);
|
||||
}
|
||||
return RedirectToAction("Index", "Manage");
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/VerifyPhoneNumber
|
||||
public async Task<IActionResult> VerifyPhoneNumber(string phoneNumber)
|
||||
{
|
||||
// This code allows you exercise the flow without actually sending codes
|
||||
// For production use please register a SMS provider in IdentityConfig and generate a code here.
|
||||
var code = await UserManager.GenerateChangePhoneNumberTokenAsync(await GetCurrentUserAsync(), phoneNumber);
|
||||
ViewBag.Status = "For DEMO purposes only, the current code is " + code;
|
||||
return phoneNumber == null ? View("Error") : View(new VerifyPhoneNumberViewModel { PhoneNumber = phoneNumber });
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/VerifyPhoneNumber
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> VerifyPhoneNumber(VerifyPhoneNumberViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var result = await UserManager.ChangePhoneNumberAsync(user, model.PhoneNumber, model.Code);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await SignInManager.SignInAsync(user, isPersistent: false);
|
||||
return RedirectToAction("Index", new { Message = ManageMessageId.AddPhoneSuccess });
|
||||
}
|
||||
}
|
||||
// If we got this far, something failed, redisplay form
|
||||
ModelState.AddModelError("", "Failed to verify phone");
|
||||
return View(model);
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/RemovePhoneNumber
|
||||
public async Task<IActionResult> RemovePhoneNumber()
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var result = await UserManager.SetPhoneNumberAsync(user, null);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await SignInManager.SignInAsync(user, isPersistent: false);
|
||||
return RedirectToAction("Index", new { Message = ManageMessageId.RemovePhoneSuccess });
|
||||
}
|
||||
}
|
||||
return RedirectToAction("Index", new { Message = ManageMessageId.Error });
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/ChangePassword
|
||||
public IActionResult ChangePassword()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Account/Manage
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> ChangePassword(ChangePasswordViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var result = await UserManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await SignInManager.SignInAsync(user, isPersistent: false);
|
||||
return RedirectToAction("Index", new { Message = ManageMessageId.ChangePasswordSuccess });
|
||||
}
|
||||
AddErrors(result);
|
||||
return View(model);
|
||||
}
|
||||
return RedirectToAction("Index", new { Message = ManageMessageId.Error });
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Manage/SetPassword
|
||||
public IActionResult SetPassword()
|
||||
{
|
||||
return View();
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/SetPassword
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> SetPassword(SetPasswordViewModel model)
|
||||
{
|
||||
if (!ModelState.IsValid)
|
||||
{
|
||||
return View(model);
|
||||
}
|
||||
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
var result = await UserManager.AddPasswordAsync(user, model.NewPassword);
|
||||
if (result.Succeeded)
|
||||
{
|
||||
await SignInManager.SignInAsync(user, isPersistent: false);
|
||||
return RedirectToAction("Index", new { Message = ManageMessageId.SetPasswordSuccess });
|
||||
}
|
||||
AddErrors(result);
|
||||
return View(model);
|
||||
}
|
||||
return RedirectToAction("Index", new { Message = ManageMessageId.Error });
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/RememberBrowser
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> RememberBrowser()
|
||||
{
|
||||
var user = await GetCurrentUserAsync();
|
||||
if (user != null)
|
||||
{
|
||||
await SignInManager.RememberTwoFactorClient(user);
|
||||
await SignInManager.SignInAsync(user, isPersistent: false);
|
||||
}
|
||||
return RedirectToAction("Index", "Manage");
|
||||
}
|
||||
|
||||
//
|
||||
// POST: /Manage/ForgetBrowser
|
||||
[HttpPost]
|
||||
[ValidateAntiForgeryToken]
|
||||
public async Task<IActionResult> ForgetBrowser()
|
||||
{
|
||||
await SignInManager.ForgetTwoFactorClientAsync();
|
||||
return RedirectToAction("Index", "Manage");
|
||||
}
|
||||
|
||||
//
|
||||
// GET: /Account/Manage
|
||||
//public async Task<IActionResult> ManageLogins(ManageMessageId? message)
|
||||
//{
|
||||
// ViewBag.StatusMessage =
|
||||
// message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
|
||||
// : message == ManageMessageId.Error ? "An error has occurred."
|
||||
// : "";
|
||||
// var user = await GetCurrentUserAsync();
|
||||
// if (user == null)
|
||||
// {
|
||||
// return View("Error");
|
||||
// }
|
||||
// var userLogins = await UserManager.GetLoginsAsync(user);
|
||||
//var otherLogins = AuthenticationManager.GetExternalAuthenticationTypes().Where(auth => userLogins.All(ul => auth.AuthenticationType != ul.LoginProvider)).ToList();
|
||||
//ViewBag.ShowRemoveButton = user.PasswordHash != null || userLogins.Count > 1;
|
||||
//return View(new ManageLoginsViewModel
|
||||
//{
|
||||
// CurrentLogins = userLogins,
|
||||
// OtherLogins = otherLogins
|
||||
//});
|
||||
//}
|
||||
|
||||
#region Helpers
|
||||
private void AddErrors(IdentityResult result)
|
||||
{
|
||||
foreach (var error in result.Errors)
|
||||
{
|
||||
ModelState.AddModelError("", error);
|
||||
}
|
||||
}
|
||||
|
||||
private async Task<bool> HasPhoneNumber()
|
||||
{
|
||||
var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
|
||||
if (user != null)
|
||||
{
|
||||
return user.PhoneNumber != null;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public enum ManageMessageId
|
||||
{
|
||||
AddPhoneSuccess,
|
||||
ChangePasswordSuccess,
|
||||
SetTwoFactorSuccess,
|
||||
SetPasswordSuccess,
|
||||
RemoveLoginSuccess,
|
||||
RemovePhoneSuccess,
|
||||
Error
|
||||
}
|
||||
|
||||
private async Task<ApplicationUser> GetCurrentUserAsync()
|
||||
{
|
||||
return await UserManager.FindByIdAsync(Context.User.Identity.GetUserId());
|
||||
}
|
||||
|
||||
private IActionResult RedirectToLocal(string returnUrl)
|
||||
{
|
||||
if (Url.IsLocalUrl(returnUrl))
|
||||
{
|
||||
return Redirect(returnUrl);
|
||||
}
|
||||
else
|
||||
{
|
||||
return RedirectToAction("Index", "Home");
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
@ -1,5 +1,5 @@
|
|||
{
|
||||
"DefaultAdminUsername": "Administrator",
|
||||
"DefaultAdminUsername": "Administrator@test.com",
|
||||
"DefaultAdminPassword": "YouShouldChangeThisPassword1!",
|
||||
"Data": {
|
||||
"DefaultConnection": {
|
||||
|
|
|
|||
|
|
@ -1,38 +1,58 @@
|
|||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
|
||||
namespace MusicStore.Models
|
||||
{
|
||||
public class ExternalLoginConfirmationViewModel
|
||||
{
|
||||
[Required]
|
||||
[Display(Name = "User name")]
|
||||
public string UserName { get; set; }
|
||||
[Display(Name = "Email")]
|
||||
public string Email { get; set; }
|
||||
}
|
||||
|
||||
public class ManageUserViewModel
|
||||
public class ExternalLoginListViewModel
|
||||
{
|
||||
public string ReturnUrl { get; set; }
|
||||
}
|
||||
|
||||
public class SendCodeViewModel
|
||||
{
|
||||
public string SelectedProvider { get; set; }
|
||||
public ICollection<SelectListItem> Providers { get; set; }
|
||||
public string ReturnUrl { get; set; }
|
||||
public bool RememberMe { get; set; }
|
||||
}
|
||||
|
||||
public class VerifyCodeViewModel
|
||||
{
|
||||
[Required]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Current password")]
|
||||
public string OldPassword { get; set; }
|
||||
public string Provider { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "New password")]
|
||||
public string NewPassword { get; set; }
|
||||
[Display(Name = "Code")]
|
||||
public string Code { get; set; }
|
||||
public string ReturnUrl { get; set; }
|
||||
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Confirm new password")]
|
||||
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
[Display(Name = "Remember this browser?")]
|
||||
public bool RememberBrowser { get; set; }
|
||||
|
||||
public bool RememberMe { get; set; }
|
||||
}
|
||||
|
||||
public class ForgotViewModel
|
||||
{
|
||||
[Required]
|
||||
[Display(Name = "Email")]
|
||||
public string Email { get; set; }
|
||||
}
|
||||
|
||||
public class LoginViewModel
|
||||
{
|
||||
[Required]
|
||||
[Display(Name = "User name")]
|
||||
public string UserName { get; set; }
|
||||
[Display(Name = "Email")]
|
||||
[EmailAddress]
|
||||
public string Email { get; set; }
|
||||
|
||||
[Required]
|
||||
[DataType(DataType.Password)]
|
||||
|
|
@ -46,8 +66,9 @@ namespace MusicStore.Models
|
|||
public class RegisterViewModel
|
||||
{
|
||||
[Required]
|
||||
[Display(Name = "User name")]
|
||||
public string UserName { get; set; }
|
||||
[EmailAddress]
|
||||
[Display(Name = "Email")]
|
||||
public string Email { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
|
||||
|
|
@ -60,4 +81,33 @@ namespace MusicStore.Models
|
|||
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
}
|
||||
|
||||
public class ResetPasswordViewModel
|
||||
{
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
[Display(Name = "Email")]
|
||||
public string Email { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Password")]
|
||||
public string Password { get; set; }
|
||||
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Confirm password")]
|
||||
[Compare("Password", ErrorMessage = "The password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
|
||||
public string Code { get; set; }
|
||||
}
|
||||
|
||||
public class ForgotPasswordViewModel
|
||||
{
|
||||
[Required]
|
||||
[EmailAddress]
|
||||
[Display(Name = "Email")]
|
||||
public string Email { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,88 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel.DataAnnotations;
|
||||
using Microsoft.AspNet.Http.Security;
|
||||
using Microsoft.AspNet.Identity;
|
||||
using Microsoft.AspNet.Mvc.Rendering;
|
||||
|
||||
namespace MusicStore.Models
|
||||
{
|
||||
public class IndexViewModel
|
||||
{
|
||||
public bool HasPassword { get; set; }
|
||||
public IList<UserLoginInfo> Logins { get; set; }
|
||||
public string PhoneNumber { get; set; }
|
||||
public bool TwoFactor { get; set; }
|
||||
public bool BrowserRemembered { get; set; }
|
||||
}
|
||||
|
||||
public class ManageLoginsViewModel
|
||||
{
|
||||
public IList<UserLoginInfo> CurrentLogins { get; set; }
|
||||
public IList<AuthenticationDescription> OtherLogins { get; set; }
|
||||
}
|
||||
|
||||
public class FactorViewModel
|
||||
{
|
||||
public string Purpose { get; set; }
|
||||
}
|
||||
|
||||
public class SetPasswordViewModel
|
||||
{
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "New password")]
|
||||
public string NewPassword { get; set; }
|
||||
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Confirm new password")]
|
||||
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
}
|
||||
|
||||
public class ChangePasswordViewModel
|
||||
{
|
||||
[Required]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Current password")]
|
||||
public string OldPassword { get; set; }
|
||||
|
||||
[Required]
|
||||
[StringLength(100, ErrorMessage = "The {0} must be at least {2} characters long.", MinimumLength = 6)]
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "New password")]
|
||||
public string NewPassword { get; set; }
|
||||
|
||||
[DataType(DataType.Password)]
|
||||
[Display(Name = "Confirm new password")]
|
||||
[Compare("NewPassword", ErrorMessage = "The new password and confirmation password do not match.")]
|
||||
public string ConfirmPassword { get; set; }
|
||||
}
|
||||
|
||||
public class AddPhoneNumberViewModel
|
||||
{
|
||||
[Required]
|
||||
[Phone]
|
||||
[Display(Name = "Phone Number")]
|
||||
public string Number { get; set; }
|
||||
}
|
||||
|
||||
public class VerifyPhoneNumberViewModel
|
||||
{
|
||||
[Required]
|
||||
[Display(Name = "Code")]
|
||||
public string Code { get; set; }
|
||||
|
||||
[Required]
|
||||
[Phone]
|
||||
[Display(Name = "Phone Number")]
|
||||
public string PhoneNumber { get; set; }
|
||||
}
|
||||
|
||||
public class ConfigureTwoFactorViewModel
|
||||
{
|
||||
public string SelectedProvider { get; set; }
|
||||
public ICollection<SelectListItem> Providers { get; set; }
|
||||
}
|
||||
}
|
||||
|
|
@ -53,9 +53,7 @@
|
|||
<Content Include="Scripts\respond.min.js" />
|
||||
<Content Include="Scripts\_references.js" />
|
||||
<Content Include="Views\Account\Login.cshtml" />
|
||||
<Content Include="Views\Account\Manage.cshtml" />
|
||||
<Content Include="Views\Account\Register.cshtml" />
|
||||
<Content Include="Views\Account\_ChangePasswordPartial.cshtml" />
|
||||
<Content Include="Views\Checkout\AddressAndPayment.cshtml" />
|
||||
<Content Include="Views\Checkout\Complete.cshtml" />
|
||||
<Content Include="Views\Home\Index.cshtml" />
|
||||
|
|
|
|||
|
|
@ -24,9 +24,9 @@ namespace MusicStore
|
|||
configuration.AddJsonFile("LocalConfig.json");
|
||||
configuration.AddEnvironmentVariables(); //All environment variables in the process's context flow in as configuration values.
|
||||
|
||||
/* Error page middleware displays a nice formatted HTML page for any unhandled exceptions in the request pipeline.
|
||||
* Note: ErrorPageOptions.ShowAll to be used only at development time. Not recommended for production.
|
||||
*/
|
||||
/* Error page middleware displays a nice formatted HTML page for any unhandled exceptions in the request pipeline.
|
||||
* Note: ErrorPageOptions.ShowAll to be used only at development time. Not recommended for production.
|
||||
*/
|
||||
app.UseErrorPage(ErrorPageOptions.ShowAll);
|
||||
|
||||
app.UseServices(services =>
|
||||
|
|
@ -78,9 +78,11 @@ namespace MusicStore
|
|||
app.UseCookieAuthentication(new CookieAuthenticationOptions
|
||||
{
|
||||
AuthenticationType = ClaimsIdentityOptions.DefaultAuthenticationType,
|
||||
LoginPath = new PathString("/Account/Login"),
|
||||
LoginPath = new PathString("/Account/Login")
|
||||
});
|
||||
|
||||
app.UseTwoFactorSignInCookies();
|
||||
|
||||
// Add MVC to the request pipeline
|
||||
app.UseMvc(routes =>
|
||||
{
|
||||
|
|
|
|||
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
ViewBag.Title = "Confirm Email";
|
||||
}
|
||||
|
||||
<h2>@ViewBag.Title.</h2>
|
||||
<div>
|
||||
<p>
|
||||
Thank you for confirming your email. Please @Html.ActionLink("Click here to Log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
@model MusicStore.Models.ExternalLoginConfirmationViewModel
|
||||
@{
|
||||
ViewBag.Title = "Register";
|
||||
}
|
||||
<h2>@ViewBag.Title.</h2>
|
||||
<h3>Associate your @ViewBag.LoginProvider account.</h3>
|
||||
|
||||
@using (Html.BeginForm("ExternalLoginConfirmation", "Account", new { ReturnUrl = ViewBag.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
|
||||
<h4>Association Form</h4>
|
||||
<hr />
|
||||
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
|
||||
<p class="text-info">
|
||||
You've successfully authenticated with <strong>@ViewBag.LoginProvider</strong>.
|
||||
Please enter a user name for this site below and click the Register button to finish
|
||||
logging in.
|
||||
</p>
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
|
||||
<div class="col-md-10">
|
||||
@Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
|
||||
@Html.ValidationMessageFor(m => m.Email, "", new { @class = "text-danger" })
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<input type="submit" class="btn btn-default" value="Register" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@section Scripts {
|
||||
@*TODO : Until script helpers are available, adding script references manually*@
|
||||
@*@Scripts.Render("~/bundles/jqueryval")*@
|
||||
<script src="@Url.Content("~/Scripts/jquery.validate.js")"></script>
|
||||
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")"></script>
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
@{
|
||||
ViewBag.Title = "Login Failure";
|
||||
}
|
||||
|
||||
<hgroup>
|
||||
<h2>@ViewBag.Title.</h2>
|
||||
<h3 class="text-danger">Unsuccessful login with service.</h3>
|
||||
</hgroup>
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
@model MusicStore.Models.ForgotPasswordViewModel
|
||||
@{
|
||||
ViewBag.Title = "Forgot your password?";
|
||||
}
|
||||
|
||||
<h2>@ViewBag.Title.</h2>
|
||||
|
||||
@using (Html.BeginForm("ForgotPassword", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
<h4>Enter your email.</h4>
|
||||
<hr />
|
||||
@Html.ValidationSummary("", new { @class = "text-danger" })
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
|
||||
<div class="col-md-10">
|
||||
@Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<input type="submit" class="btn btn-default" value="Email Link" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@section Scripts {
|
||||
@*TODO : Until script helpers are available, adding script references manually*@
|
||||
@*@Scripts.Render("~/bundles/jqueryval")*@
|
||||
<script src="@Url.Content("~/Scripts/jquery.validate.js")"></script>
|
||||
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")"></script>
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
@{
|
||||
ViewBag.Title = "Forgot Password Confirmation";
|
||||
}
|
||||
|
||||
<hgroup class="title">
|
||||
<h1>@ViewBag.Title.</h1>
|
||||
</hgroup>
|
||||
<div>
|
||||
<p>
|
||||
Please check your email to reset your password.
|
||||
</p>
|
||||
<p>
|
||||
For demo purpose only: @Html.ActionLink("Click here to reset the password: ", "ResetPassword", new { code = ViewBag.Code });
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -1,4 +1,5 @@
|
|||
@model MusicStore.Models.LoginViewModel
|
||||
@using MusicStore.Models
|
||||
@model LoginViewModel
|
||||
|
||||
@{
|
||||
ViewBag.Title = "Log in";
|
||||
|
|
@ -13,19 +14,19 @@
|
|||
@Html.AntiForgeryToken()
|
||||
<h4>Use a local account to log in.</h4>
|
||||
<hr />
|
||||
@Html.ValidationSummary(true)
|
||||
@Html.ValidationSummary(true, "", new { @class = "text-danger" })
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" })
|
||||
@Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
|
||||
<div class="col-md-10">
|
||||
@Html.TextBoxFor(m => m.UserName, new { @class = "form-control" })
|
||||
@Html.ValidationMessageFor(m => m.UserName)
|
||||
@Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
|
||||
@Html.ValidationMessageFor(m => m.Email, "", new { @class = "text-danger" })
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
|
||||
<div class="col-md-10">
|
||||
@Html.PasswordFor(m => m.Password, new { @class = "form-control" })
|
||||
@Html.ValidationMessageFor(m => m.Password)
|
||||
@Html.ValidationMessageFor(m => m.Password, "", new { @class = "text-danger" })
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
|
|
@ -42,11 +43,20 @@
|
|||
</div>
|
||||
</div>
|
||||
<p>
|
||||
@Html.ActionLink("Register", "Register") if you don't have a local account.
|
||||
@Html.ActionLink("Register as a new user", "Register")
|
||||
</p>
|
||||
@*Enable this once you have account confirmation enabled for password reset functionality*@
|
||||
<p>
|
||||
@Html.ActionLink("Forgot your password?", "ForgotPassword")
|
||||
</p>
|
||||
}
|
||||
</section>
|
||||
</div>
|
||||
@*<div class="col-md-4">
|
||||
<section id="socialLoginForm">
|
||||
@Html.PartialAsync("_ExternalLoginsListPartial", new ExternalLoginListViewModel { ReturnUrl = ViewBag.ReturnUrl })
|
||||
</section>
|
||||
</div>*@
|
||||
</div>
|
||||
@section Scripts {
|
||||
@*TODO : Until script helpers are available, adding script references manually*@
|
||||
|
|
|
|||
|
|
@ -1,19 +0,0 @@
|
|||
@{
|
||||
ViewBag.Title = "Manage Account";
|
||||
}
|
||||
|
||||
<h2>@ViewBag.Title.</h2>
|
||||
<p class="text-success">@ViewBag.StatusMessage</p>
|
||||
|
||||
<div class="row">
|
||||
<div class="col-md-12">
|
||||
@await Html.PartialAsync("_ChangePasswordPartial")
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@section Scripts {
|
||||
@*TODO : Until script helpers are available, adding script references manually*@
|
||||
@*@Scripts.Render("~/bundles/jqueryval")*@
|
||||
<script src="@Url.Content("~/Scripts/jquery.validate.js")"></script>
|
||||
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")"></script>
|
||||
}
|
||||
|
|
@ -10,11 +10,11 @@
|
|||
@Html.AntiForgeryToken()
|
||||
<h4>Create a new account.</h4>
|
||||
<hr />
|
||||
@Html.ValidationSummary()
|
||||
@Html.ValidationSummary("", new { @class = "text-danger" })
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(m => m.UserName, new { @class = "col-md-2 control-label" })
|
||||
@Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
|
||||
<div class="col-md-10">
|
||||
@Html.TextBoxFor(m => m.UserName, new { @class = "form-control" })
|
||||
@Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
|
|
|
|||
|
|
@ -0,0 +1,15 @@
|
|||
@{
|
||||
ViewBag.Title = "Register Confirmation";
|
||||
}
|
||||
|
||||
<hgroup class="title">
|
||||
<h1>@ViewBag.Title.</h1>
|
||||
</hgroup>
|
||||
<div>
|
||||
<p>
|
||||
Please check your email to activate your account.
|
||||
</p>
|
||||
<p>
|
||||
Demo/testing purposes only: The sample displays the code and user id in the page: @Html.ActionLink("Click here to confirm your email: ", "ConfirmEmail", new { code = ViewBag.Code, userId = ViewBag.UserId })
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
@model MusicStore.Models.ResetPasswordViewModel
|
||||
@{
|
||||
ViewBag.Title = "Reset password";
|
||||
}
|
||||
|
||||
<h2>@ViewBag.Title.</h2>
|
||||
|
||||
@using (Html.BeginForm("ResetPassword", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
<h4>Reset your password.</h4>
|
||||
<hr />
|
||||
@Html.ValidationSummary("", new { @class = "text-danger" })
|
||||
@Html.HiddenFor(model => model.Code)
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
|
||||
<div class="col-md-10">
|
||||
@Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
|
||||
<div class="col-md-10">
|
||||
@Html.PasswordFor(m => m.Password, new { @class = "form-control" })
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" })
|
||||
<div class="col-md-10">
|
||||
@Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" })
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<input type="submit" class="btn btn-default" value="Reset" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@section Scripts {
|
||||
@*TODO : Until script helpers are available, adding script references manually*@
|
||||
@*@Scripts.Render("~/bundles/jqueryval")*@
|
||||
<script src="@Url.Content("~/Scripts/jquery.validate.js")"></script>
|
||||
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")"></script>
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
@{
|
||||
ViewBag.Title = "Reset password confirmation";
|
||||
}
|
||||
|
||||
<hgroup class="title">
|
||||
<h1>@ViewBag.Title.</h1>
|
||||
</hgroup>
|
||||
<div>
|
||||
<p>
|
||||
Your password has been reset. Please @Html.ActionLink("click here to log in", "Login", "Account", routeValues: null, htmlAttributes: new { id = "loginLink" })
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
@model MusicStore.Models.SendCodeViewModel
|
||||
@{
|
||||
ViewBag.Title = "Send";
|
||||
}
|
||||
|
||||
<h2>@ViewBag.Title.</h2>
|
||||
|
||||
@using (Html.BeginForm("SendCode", "Account", new { ReturnUrl = Model.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) {
|
||||
@Html.AntiForgeryToken()
|
||||
@Html.Hidden("rememberMe", @Model.RememberMe)
|
||||
<h4>Send verification code</h4>
|
||||
<hr />
|
||||
<div class="row">
|
||||
<div class="col-md-8">
|
||||
Select Two-Factor Authentication Provider:
|
||||
@Html.DropDownListFor(model => model.SelectedProvider, Model.Providers)
|
||||
<input type="submit" value="Submit" class="btn btn-default" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@section Scripts {
|
||||
@*TODO : Until script helpers are available, adding script references manually*@
|
||||
@*@Scripts.Render("~/bundles/jqueryval")*@
|
||||
<script src="@Url.Content("~/Scripts/jquery.validate.js")"></script>
|
||||
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")"></script>
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
@model MusicStore.Models.ExternalLoginListViewModel
|
||||
@using Microsoft.AspNet.Http.Security;
|
||||
|
||||
<h4>Use another service to log in.</h4>
|
||||
<hr />
|
||||
@{
|
||||
var loginProviders = Context.GetAuthenticationTypes();
|
||||
if (loginProviders.Count() == 0) {
|
||||
<div>
|
||||
<p>
|
||||
There are no external authentication services configured. See <a href="http://go.microsoft.com/fwlink/?LinkId=313242">this article</a>
|
||||
for details on setting up this ASP.NET application to support logging in via external services.
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
else {
|
||||
using (Html.BeginForm("ExternalLogin", "Account", new { ReturnUrl = Model.ReturnUrl })) {
|
||||
@Html.AntiForgeryToken()
|
||||
<div id="socialLoginList">
|
||||
<p>
|
||||
@foreach (AuthenticationDescription p in loginProviders) {
|
||||
<button type="submit" class="btn btn-default" id="@p.AuthenticationType" name="provider" value="@p.AuthenticationType" title="Log in using your @p.Caption account">@p.AuthenticationType</button>
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,32 @@
|
|||
@model MusicStore.Models.AddPhoneNumberViewModel
|
||||
@{
|
||||
ViewBag.Title = "Phone Number";
|
||||
}
|
||||
|
||||
<h2>@ViewBag.Title.</h2>
|
||||
|
||||
@using (Html.BeginForm("AddPhoneNumber", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
<h4>Add a phone number</h4>
|
||||
<hr />
|
||||
@Html.ValidationSummary("", new { @class = "text-danger" })
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(m => m.Number, new { @class = "col-md-2 control-label" })
|
||||
<div class="col-md-10">
|
||||
@Html.TextBoxFor(m => m.Number, new { @class = "form-control" })
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<input type="submit" class="btn btn-default" value="Submit" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@section Scripts {
|
||||
@*TODO : Until script helpers are available, adding script references manually*@
|
||||
@*@Scripts.Render("~/bundles/jqueryval")*@
|
||||
<script src="@Url.Content("~/Scripts/jquery.validate.js")"></script>
|
||||
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")"></script>
|
||||
}
|
||||
|
|
@ -1,14 +1,16 @@
|
|||
@using System.Security.Principal
|
||||
@model MusicStore.Models.ManageUserViewModel
|
||||
@model MusicStore.Models.ChangePasswordViewModel
|
||||
@{
|
||||
ViewBag.Title = "Change Password";
|
||||
}
|
||||
|
||||
<p>You're logged in as <strong>@User.Identity.GetUserName()</strong>.</p>
|
||||
<h2>@ViewBag.Title.</h2>
|
||||
|
||||
@using (Html.BeginForm("Manage", "Account", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
|
||||
@using (Html.BeginForm("ChangePassword", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
<h4>Change Password Form</h4>
|
||||
<hr />
|
||||
@Html.ValidationSummary()
|
||||
@Html.ValidationSummary("", new { @class = "text-danger" })
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(m => m.OldPassword, new { @class = "col-md-2 control-label" })
|
||||
<div class="col-md-10">
|
||||
|
|
@ -27,10 +29,15 @@
|
|||
@Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" })
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<input type="submit" value="Change password" class="btn btn-default" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
@section Scripts {
|
||||
@*TODO : Until script helpers are available, adding script references manually*@
|
||||
@*@Scripts.Render("~/bundles/jqueryval")*@
|
||||
<script src="@Url.Content("~/Scripts/jquery.validate.js")"></script>
|
||||
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")"></script>
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
@model MusicStore.Models.IndexViewModel
|
||||
@{
|
||||
ViewBag.Title = "Manage";
|
||||
}
|
||||
|
||||
<h2>@ViewBag.Title.</h2>
|
||||
|
||||
<p class="text-success">@ViewBag.StatusMessage</p>
|
||||
<div>
|
||||
<h4>Change your account settings</h4>
|
||||
<hr />
|
||||
<dl class="dl-horizontal">
|
||||
<dt>Password:</dt>
|
||||
<dd>
|
||||
[
|
||||
@if (Model.HasPassword)
|
||||
{
|
||||
@Html.ActionLink("Change your password", "ChangePassword")
|
||||
}
|
||||
else
|
||||
{
|
||||
@Html.ActionLink("Create", "SetPassword")
|
||||
}
|
||||
]
|
||||
</dd>
|
||||
<dt>External Logins:</dt>
|
||||
<dd>
|
||||
@Model.Logins.Count [
|
||||
@Html.ActionLink("Manage", "ManageLogins") ]
|
||||
</dd>
|
||||
@*
|
||||
Phone Numbers can used as a second factor of verification in a two-factor authentication system.
|
||||
|
||||
See <a href="http://go.microsoft.com/fwlink/?LinkId=313242">this article</a>
|
||||
for details on setting up this ASP.NET application to support two-factor authentication using SMS.
|
||||
|
||||
Uncomment the following block after you have set up two-factor authentication
|
||||
*@
|
||||
|
||||
<dt>Phone Number:</dt>
|
||||
<dd>
|
||||
@(Model.PhoneNumber ?? "None") [
|
||||
@if (Model.PhoneNumber != null)
|
||||
{
|
||||
@Html.ActionLink("Change", "AddPhoneNumber")
|
||||
@: |
|
||||
@Html.ActionLink("Remove", "RemovePhoneNumber")
|
||||
}
|
||||
else
|
||||
{
|
||||
@Html.ActionLink("Add", "AddPhoneNumber")
|
||||
}
|
||||
]
|
||||
</dd>
|
||||
<dt>Two-Factor Authentication:</dt>
|
||||
<dd>
|
||||
@if (Model.TwoFactor)
|
||||
{
|
||||
using (Html.BeginForm("DisableTwoFactorAuthentication", "Manage", FormMethod.Post))
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
<p>
|
||||
Enabled
|
||||
<input type="submit" value="Disable" class="btn btn-link" />
|
||||
</p>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (Html.BeginForm("EnableTwoFactorAuthentication", "Manage", FormMethod.Post))
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
<p>
|
||||
Disabled
|
||||
<input type="submit" value="Enable" class="btn btn-link" />
|
||||
</p>
|
||||
}
|
||||
}
|
||||
</dd>
|
||||
<dt>Browser remembered:</dt>
|
||||
<dd>
|
||||
@if (Model.BrowserRemembered)
|
||||
{
|
||||
using (Html.BeginForm("ForgetBrowser", "Manage", FormMethod.Post))
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
<p>
|
||||
Browser is curently remembered for two factor:
|
||||
<input type="submit" value="Forget Browser" class="btn btn-default" />
|
||||
</p>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
using (Html.BeginForm("RememberBrowser", "Manage", FormMethod.Post))
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
<p>
|
||||
Browser is curently not remembered for two factor:
|
||||
<input type="submit" value="Remember Browser" class="btn btn-default" />
|
||||
</p>
|
||||
}
|
||||
}
|
||||
</dd>
|
||||
</dl>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
@using Microsoft.AspNet.Http.Security;
|
||||
@model MusicStore.Models.ManageLoginsViewModel
|
||||
@{
|
||||
ViewBag.Title = "Manage your external logins";
|
||||
}
|
||||
|
||||
<h2>@ViewBag.Title.</h2>
|
||||
|
||||
<p class="text-success">@ViewBag.StatusMessage</p>
|
||||
@if (Model.CurrentLogins.Count > 0)
|
||||
{
|
||||
<h4>Registered Logins</h4>
|
||||
<table class="table">
|
||||
<tbody>
|
||||
@foreach (var account in Model.CurrentLogins)
|
||||
{
|
||||
<tr>
|
||||
<td>@account.LoginProvider</td>
|
||||
<td>
|
||||
@if (ViewBag.ShowRemoveButton)
|
||||
{
|
||||
using (Html.BeginForm("RemoveLogin", "Manage"))
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
<div>
|
||||
@Html.Hidden("loginProvider", account.LoginProvider)
|
||||
@Html.Hidden("providerKey", account.ProviderKey)
|
||||
<input type="submit" class="btn btn-default" value="Remove" title="Remove this @account.LoginProvider login from your account" />
|
||||
</div>
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@:
|
||||
}
|
||||
</td>
|
||||
</tr>
|
||||
}
|
||||
</tbody>
|
||||
</table>
|
||||
}
|
||||
@if (Model.OtherLogins.Count > 0)
|
||||
{
|
||||
<h4>Add another service to log in.</h4>
|
||||
<hr />
|
||||
using (Html.BeginForm("LinkLogin", "Manage"))
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
<div id="socialLoginList">
|
||||
<p>
|
||||
@foreach (AuthenticationDescription p in Model.OtherLogins)
|
||||
{
|
||||
<button type="submit" class="btn btn-default" id="@p.AuthenticationType" name="provider" value="@p.AuthenticationType" title="Log in using your @p.Caption account">@p.AuthenticationType</button>
|
||||
}
|
||||
</p>
|
||||
</div>
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
@model MusicStore.Models.SetPasswordViewModel
|
||||
@{
|
||||
ViewBag.Title = "Create Password";
|
||||
}
|
||||
|
||||
<h2>@ViewBag.Title.</h2>
|
||||
<p class="text-info">
|
||||
You do not have a local username/password for this site. Add a local
|
||||
account so you can log in without an external login.
|
||||
</p>
|
||||
|
||||
@using (Html.BeginForm("SetPassword", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
|
||||
<h4>Create Local Login</h4>
|
||||
<hr />
|
||||
@Html.ValidationSummary("", new { @class = "text-danger" })
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(m => m.NewPassword, new { @class = "col-md-2 control-label" })
|
||||
<div class="col-md-10">
|
||||
@Html.PasswordFor(m => m.NewPassword, new { @class = "form-control" })
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" })
|
||||
<div class="col-md-10">
|
||||
@Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" })
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<input type="submit" value="Set password" class="btn btn-default" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@section Scripts {
|
||||
@*TODO : Until script helpers are available, adding script references manually*@
|
||||
@*@Scripts.Render("~/bundles/jqueryval")*@
|
||||
<script src="@Url.Content("~/Scripts/jquery.validate.js")"></script>
|
||||
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")"></script>
|
||||
}
|
||||
|
|
@ -0,0 +1,34 @@
|
|||
@model MusicStore.Models.VerifyPhoneNumberViewModel
|
||||
@{
|
||||
ViewBag.Title = "Verify Phone Number";
|
||||
}
|
||||
|
||||
<h2>@ViewBag.Title.</h2>
|
||||
|
||||
@using (Html.BeginForm("VerifyPhoneNumber", "Manage", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
|
||||
{
|
||||
@Html.AntiForgeryToken()
|
||||
@Html.Hidden("phoneNumber", @Model.PhoneNumber)
|
||||
<h4>Enter verification code</h4>
|
||||
<h5>@ViewBag.Status</h5>
|
||||
<hr />
|
||||
@Html.ValidationSummary("", new { @class = "text-danger" })
|
||||
<div class="form-group">
|
||||
@Html.LabelFor(m => m.Code, new { @class = "col-md-2 control-label" })
|
||||
<div class="col-md-10">
|
||||
@Html.TextBoxFor(m => m.Code, new { @class = "form-control" })
|
||||
</div>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<div class="col-md-offset-2 col-md-10">
|
||||
<input type="submit" class="btn btn-default" value="Submit" />
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
|
||||
@section Scripts {
|
||||
@*TODO : Until script helpers are available, adding script references manually*@
|
||||
@*@Scripts.Render("~/bundles/jqueryval")*@
|
||||
<script src="@Url.Content("~/Scripts/jquery.validate.js")"></script>
|
||||
<script src="@Url.Content("~/Scripts/jquery.validate.unobtrusive.js")"></script>
|
||||
}
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
@{
|
||||
ViewBag.Title = "Demo code display page - Not for production use";
|
||||
}
|
||||
|
||||
<hgroup class="title">
|
||||
<h1>@ViewBag.Title.</h1>
|
||||
</hgroup>
|
||||
<div>
|
||||
<p>
|
||||
Demo code display page - Not for production use.
|
||||
</p>
|
||||
<p>
|
||||
[Demo]: @ViewBag.Status
|
||||
</p>
|
||||
</div>
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
@{
|
||||
ViewBag.Title = "Locked Out";
|
||||
}
|
||||
|
||||
<hgroup>
|
||||
<h1 class="text-danger">Locked out.</h1>
|
||||
<h2 class="text-danger">This account has been locked out, please try again later.</h2>
|
||||
</hgroup>
|
||||
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li>
|
||||
@Html.ActionLink("Hello " + User.Identity.GetUserName() + "!", "Manage", "Account", routeValues: null, htmlAttributes: new { title = "Manage" })
|
||||
@Html.ActionLink("Hello " + User.Identity.GetUserName() + "!", "Index", "Manage", routeValues: null, htmlAttributes: new { title = "Manage" })
|
||||
</li>
|
||||
<li><a href="javascript:document.getElementById('logoutForm').submit()">Log off</a></li>
|
||||
</ul>
|
||||
|
|
|
|||
|
|
@ -97,36 +97,36 @@ namespace E2ETests
|
|||
RegisterUserWithNonMatchingPasswords();
|
||||
|
||||
//Register a valid user
|
||||
var generatedUserName = RegisterValidUser();
|
||||
var generatedEmail = RegisterValidUser();
|
||||
|
||||
//Register a user - Negative scenario : Trying to register a user name that's already registered.
|
||||
RegisterExistingUser(generatedUserName);
|
||||
RegisterExistingUser(generatedEmail);
|
||||
|
||||
//Logout from this user session - This should take back to the home page
|
||||
SignOutUser(generatedUserName);
|
||||
SignOutUser(generatedEmail);
|
||||
|
||||
//Sign in scenarios: Invalid password - Expected an invalid user name password error.
|
||||
SignInWithInvalidPassword(generatedUserName, "InvalidPassword~1");
|
||||
SignInWithInvalidPassword(generatedEmail, "InvalidPassword~1");
|
||||
|
||||
//Sign in scenarios: Valid user name & password.
|
||||
SignInWithUser(generatedUserName, "Password~1");
|
||||
SignInWithUser(generatedEmail, "Password~1");
|
||||
|
||||
//Change password scenario
|
||||
ChangePassword(generatedUserName);
|
||||
ChangePassword(generatedEmail);
|
||||
|
||||
//SignIn with old password and verify old password is not allowed and new password is allowed
|
||||
SignOutUser(generatedUserName);
|
||||
SignInWithInvalidPassword(generatedUserName, "Password~1");
|
||||
SignInWithUser(generatedUserName, "Password~2");
|
||||
SignOutUser(generatedEmail);
|
||||
SignInWithInvalidPassword(generatedEmail, "Password~1");
|
||||
SignInWithUser(generatedEmail, "Password~2");
|
||||
|
||||
//Making a request to a protected resource that this user does not have access to - should automatically redirect to login page again
|
||||
AccessStoreWithoutPermissions(generatedUserName);
|
||||
AccessStoreWithoutPermissions(generatedEmail);
|
||||
|
||||
//Logout from this user session - This should take back to the home page
|
||||
SignOutUser(generatedUserName);
|
||||
SignOutUser(generatedEmail);
|
||||
|
||||
//Login as an admin user
|
||||
SignInWithUser("Administrator", "YouShouldChangeThisPassword1!");
|
||||
SignInWithUser("Administrator@test.com", "YouShouldChangeThisPassword1!");
|
||||
|
||||
//Now navigating to the store manager should work fine as this user has the necessary permission to administer the store.
|
||||
AccessStoreWithPermissions();
|
||||
|
|
@ -222,9 +222,9 @@ namespace E2ETests
|
|||
Assert.Contains("<li class=\"divider\"></li>", responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
}
|
||||
|
||||
private void AccessStoreWithoutPermissions(string userName = null)
|
||||
private void AccessStoreWithoutPermissions(string email = null)
|
||||
{
|
||||
Console.WriteLine("Trying to access StoreManager that needs ManageStore claim with the current user : {0}", userName ?? "Anonymous");
|
||||
Console.WriteLine("Trying to access StoreManager that needs ManageStore claim with the current user : {0}", email ?? "Anonymous");
|
||||
var response = httpClient.GetAsync("StoreManager/").Result;
|
||||
ThrowIfResponseStatusNotOk(response);
|
||||
var responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
|
|
@ -259,11 +259,11 @@ namespace E2ETests
|
|||
var responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
ValidateLayoutPage(responseContent);
|
||||
|
||||
var generatedUserName = Guid.NewGuid().ToString().Replace("-", string.Empty);
|
||||
Console.WriteLine("Creating a new user with name '{0}'", generatedUserName);
|
||||
var generatedEmail = Guid.NewGuid().ToString().Replace("-", string.Empty) + "@test.com";
|
||||
Console.WriteLine("Creating a new user with name '{0}'", generatedEmail);
|
||||
var formParameters = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string, string>("UserName", generatedUserName),
|
||||
new KeyValuePair<string, string>("Email", generatedEmail),
|
||||
new KeyValuePair<string, string>("Password", "Password~1"),
|
||||
new KeyValuePair<string, string>("ConfirmPassword", "Password~2"),
|
||||
new KeyValuePair<string, string>("__RequestVerificationToken", HtmlDOMHelper.RetrieveAntiForgeryToken(responseContent, "/Account/Register")),
|
||||
|
|
@ -273,8 +273,8 @@ namespace E2ETests
|
|||
response = httpClient.PostAsync("Account/Register", content).Result;
|
||||
responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
Assert.Null(httpClientHandler.CookieContainer.GetCookies(new Uri(ApplicationBaseUrl)).GetCookieWithName(".AspNet.Microsoft.AspNet.Identity.Application"));
|
||||
Assert.Contains("<div class=\"validation-summary-errors\" data-valmsg-summary=\"true\"><ul><li>The password and confirmation password do not match.</li>", responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
Console.WriteLine("Server side model validator rejected the user '{0}''s registration as passwords do not match.", generatedUserName);
|
||||
Assert.Contains("<div class=\"validation-summary-errors text-danger\" data-valmsg-summary=\"true\"><ul><li>The password and confirmation password do not match.</li>", responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
Console.WriteLine("Server side model validator rejected the user '{0}''s registration as passwords do not match.", generatedEmail);
|
||||
}
|
||||
|
||||
private string RegisterValidUser()
|
||||
|
|
@ -284,11 +284,11 @@ namespace E2ETests
|
|||
var responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
ValidateLayoutPage(responseContent);
|
||||
|
||||
var generatedUserName = Guid.NewGuid().ToString().Replace("-", string.Empty);
|
||||
Console.WriteLine("Creating a new user with name '{0}'", generatedUserName);
|
||||
var generatedEmail = Guid.NewGuid().ToString().Replace("-", string.Empty) + "@test.com";
|
||||
Console.WriteLine("Creating a new user with name '{0}'", generatedEmail);
|
||||
var formParameters = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string, string>("UserName", generatedUserName),
|
||||
new KeyValuePair<string, string>("Email", generatedEmail),
|
||||
new KeyValuePair<string, string>("Password", "Password~1"),
|
||||
new KeyValuePair<string, string>("ConfirmPassword", "Password~1"),
|
||||
new KeyValuePair<string, string>("__RequestVerificationToken", HtmlDOMHelper.RetrieveAntiForgeryToken(responseContent, "/Account/Register")),
|
||||
|
|
@ -297,24 +297,24 @@ namespace E2ETests
|
|||
var content = new FormUrlEncodedContent(formParameters.ToArray());
|
||||
response = httpClient.PostAsync("Account/Register", content).Result;
|
||||
responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
Assert.Contains(string.Format("Hello {0}!", generatedUserName), responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Contains(string.Format("Hello {0}!", generatedEmail), responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Contains("Log off", responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
//Verify cookie sent
|
||||
Assert.NotNull(httpClientHandler.CookieContainer.GetCookies(new Uri(ApplicationBaseUrl)).GetCookieWithName(".AspNet.Microsoft.AspNet.Identity.Application"));
|
||||
Console.WriteLine("Successfully registered user '{0}' and signed in", generatedUserName);
|
||||
return generatedUserName;
|
||||
Console.WriteLine("Successfully registered user '{0}' and signed in", generatedEmail);
|
||||
return generatedEmail;
|
||||
}
|
||||
|
||||
private void RegisterExistingUser(string userName)
|
||||
private void RegisterExistingUser(string email)
|
||||
{
|
||||
Console.WriteLine("Trying to register a user with name '{0}' again", userName);
|
||||
Console.WriteLine("Trying to register a user with name '{0}' again", email);
|
||||
var response = httpClient.GetAsync("Account/Register").Result;
|
||||
ThrowIfResponseStatusNotOk(response);
|
||||
var responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
Console.WriteLine("Creating a new user with name '{0}'", userName);
|
||||
Console.WriteLine("Creating a new user with name '{0}'", email);
|
||||
var formParameters = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string, string>("UserName", userName),
|
||||
new KeyValuePair<string, string>("Email", email),
|
||||
new KeyValuePair<string, string>("Password", "Password~1"),
|
||||
new KeyValuePair<string, string>("ConfirmPassword", "Password~1"),
|
||||
new KeyValuePair<string, string>("__RequestVerificationToken", HtmlDOMHelper.RetrieveAntiForgeryToken(responseContent, "/Account/Register")),
|
||||
|
|
@ -323,13 +323,13 @@ namespace E2ETests
|
|||
var content = new FormUrlEncodedContent(formParameters.ToArray());
|
||||
response = httpClient.PostAsync("Account/Register", content).Result;
|
||||
responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
Assert.Contains(string.Format("Name {0} is already taken.", userName), responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
Console.WriteLine("Identity threw a valid exception that user '{0}' already exists in the system", userName);
|
||||
Assert.Contains(string.Format("Name {0} is already taken.", email), responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
Console.WriteLine("Identity threw a valid exception that user '{0}' already exists in the system", email);
|
||||
}
|
||||
|
||||
private void SignOutUser(string userName)
|
||||
private void SignOutUser(string email)
|
||||
{
|
||||
Console.WriteLine("Signing out from '{0}''s session", userName);
|
||||
Console.WriteLine("Signing out from '{0}''s session", email);
|
||||
var response = httpClient.GetAsync(string.Empty).Result;
|
||||
ThrowIfResponseStatusNotOk(response);
|
||||
var responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
|
|
@ -352,7 +352,7 @@ namespace E2ETests
|
|||
Assert.Contains("/Images/home-showcase.png", responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
//Verify cookie cleared on logout
|
||||
Assert.Null(httpClientHandler.CookieContainer.GetCookies(new Uri(ApplicationBaseUrl)).GetCookieWithName(".AspNet.Microsoft.AspNet.Identity.Application"));
|
||||
Console.WriteLine("Successfully signed out of '{0}''s session", userName);
|
||||
Console.WriteLine("Successfully signed out of '{0}''s session", email);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -362,15 +362,15 @@ namespace E2ETests
|
|||
}
|
||||
}
|
||||
|
||||
private void SignInWithInvalidPassword(string userName, string invalidPassword)
|
||||
private void SignInWithInvalidPassword(string email, string invalidPassword)
|
||||
{
|
||||
var response = httpClient.GetAsync("Account/Login").Result;
|
||||
ThrowIfResponseStatusNotOk(response);
|
||||
var responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
Console.WriteLine("Signing in with user '{0}'", userName);
|
||||
Console.WriteLine("Signing in with user '{0}'", email);
|
||||
var formParameters = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string, string>("UserName", userName),
|
||||
new KeyValuePair<string, string>("Email", email),
|
||||
new KeyValuePair<string, string>("Password", invalidPassword),
|
||||
new KeyValuePair<string, string>("__RequestVerificationToken", HtmlDOMHelper.RetrieveAntiForgeryToken(responseContent, "/Account/Login")),
|
||||
};
|
||||
|
|
@ -378,21 +378,21 @@ namespace E2ETests
|
|||
var content = new FormUrlEncodedContent(formParameters.ToArray());
|
||||
response = httpClient.PostAsync("Account/Login", content).Result;
|
||||
responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
Assert.Contains("<div class=\"validation-summary-errors\"><ul><li>Invalid username or password.</li>", responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Contains("<div class=\"validation-summary-errors text-danger\"><ul><li>Invalid login attempt.</li>", responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
//Verify cookie not sent
|
||||
Assert.Null(httpClientHandler.CookieContainer.GetCookies(new Uri(ApplicationBaseUrl)).GetCookieWithName(".AspNet.Microsoft.AspNet.Identity.Application"));
|
||||
Console.WriteLine("Identity successfully prevented an invalid user login.");
|
||||
}
|
||||
|
||||
private void SignInWithUser(string userName, string password)
|
||||
private void SignInWithUser(string email, string password)
|
||||
{
|
||||
var response = httpClient.GetAsync("Account/Login").Result;
|
||||
ThrowIfResponseStatusNotOk(response);
|
||||
var responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
Console.WriteLine("Signing in with user '{0}'", userName);
|
||||
Console.WriteLine("Signing in with user '{0}'", email);
|
||||
var formParameters = new List<KeyValuePair<string, string>>
|
||||
{
|
||||
new KeyValuePair<string, string>("UserName", userName),
|
||||
new KeyValuePair<string, string>("Email", email),
|
||||
new KeyValuePair<string, string>("Password", password),
|
||||
new KeyValuePair<string, string>("__RequestVerificationToken", HtmlDOMHelper.RetrieveAntiForgeryToken(responseContent, "/Account/Login")),
|
||||
};
|
||||
|
|
@ -400,16 +400,16 @@ namespace E2ETests
|
|||
var content = new FormUrlEncodedContent(formParameters.ToArray());
|
||||
response = httpClient.PostAsync("Account/Login", content).Result;
|
||||
responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
Assert.Contains(string.Format("Hello {0}!", userName), responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Contains(string.Format("Hello {0}!", email), responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.Contains("Log off", responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
//Verify cookie sent
|
||||
Assert.NotNull(httpClientHandler.CookieContainer.GetCookies(new Uri(ApplicationBaseUrl)).GetCookieWithName(".AspNet.Microsoft.AspNet.Identity.Application"));
|
||||
Console.WriteLine("Successfully signed in with user '{0}'", userName);
|
||||
Console.WriteLine("Successfully signed in with user '{0}'", email);
|
||||
}
|
||||
|
||||
private void ChangePassword(string userName)
|
||||
private void ChangePassword(string email)
|
||||
{
|
||||
var response = httpClient.GetAsync("Account/Manage").Result;
|
||||
var response = httpClient.GetAsync("Manage/ChangePassword").Result;
|
||||
ThrowIfResponseStatusNotOk(response);
|
||||
var responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
var formParameters = new List<KeyValuePair<string, string>>
|
||||
|
|
@ -417,15 +417,15 @@ namespace E2ETests
|
|||
new KeyValuePair<string, string>("OldPassword", "Password~1"),
|
||||
new KeyValuePair<string, string>("NewPassword", "Password~2"),
|
||||
new KeyValuePair<string, string>("ConfirmPassword", "Password~2"),
|
||||
new KeyValuePair<string, string>("__RequestVerificationToken", HtmlDOMHelper.RetrieveAntiForgeryToken(responseContent, "/Account/Manage")),
|
||||
new KeyValuePair<string, string>("__RequestVerificationToken", HtmlDOMHelper.RetrieveAntiForgeryToken(responseContent, "/Manage/ChangePassword")),
|
||||
};
|
||||
|
||||
var content = new FormUrlEncodedContent(formParameters.ToArray());
|
||||
response = httpClient.PostAsync("Account/Manage", content).Result;
|
||||
response = httpClient.PostAsync("Manage/ChangePassword", content).Result;
|
||||
responseContent = response.Content.ReadAsStringAsync().Result;
|
||||
Assert.Contains("Your password has been changed.", responseContent, StringComparison.OrdinalIgnoreCase);
|
||||
Assert.NotNull(httpClientHandler.CookieContainer.GetCookies(new Uri(ApplicationBaseUrl)).GetCookieWithName(".AspNet.Microsoft.AspNet.Identity.Application"));
|
||||
Console.WriteLine("Successfully changed the password for user '{0}'", userName);
|
||||
Console.WriteLine("Successfully changed the password for user '{0}'", email);
|
||||
}
|
||||
|
||||
private string CreateAlbum()
|
||||
|
|
|
|||
Loading…
Reference in New Issue