380 lines
14 KiB
C#
380 lines
14 KiB
C#
using Microsoft.AspNet.Identity;
|
|
using Microsoft.AspNet.Mvc;
|
|
using IdentitySample.Models;
|
|
using System.Security.Principal;
|
|
using System.Threading.Tasks;
|
|
|
|
namespace IdentitySample
|
|
{
|
|
[Authorize]
|
|
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: /Account/Index
|
|
public async Task<IActionResult> 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 provider has been set."
|
|
: message == ManageMessageId.Error ? "An error has occurred."
|
|
: message == ManageMessageId.AddPhoneSuccess ? "The 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.IsTwoFactorClientRemembered(user)
|
|
};
|
|
return View(model);
|
|
}
|
|
|
|
//
|
|
// GET: /Account/RemoveLogin
|
|
public async Task<IActionResult> RemoveLogin()
|
|
{
|
|
var user = await GetCurrentUserAsync();
|
|
var linkedAccounts = await UserManager.GetLoginsAsync(user);
|
|
ViewBag.ShowRemoveButton = await UserManager.HasPasswordAsync(user) || linkedAccounts.Count > 1;
|
|
return View(linkedAccounts);
|
|
}
|
|
|
|
//
|
|
// 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, new UserLoginInfo(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
|
|
#if NET45
|
|
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);
|
|
}
|
|
#endif
|
|
return RedirectToAction("VerifyPhoneNumber", new { PhoneNumber = model.Number });
|
|
}
|
|
|
|
//
|
|
// POST: /Manage/RememberBrowser
|
|
[HttpPost]
|
|
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]
|
|
public async Task<IActionResult> ForgetBrowser()
|
|
{
|
|
await SignInManager.ForgetTwoFactorClientAsync();
|
|
return RedirectToAction("Index", "Manage");
|
|
}
|
|
|
|
//
|
|
// POST: /Manage/EnableTFA
|
|
[HttpPost]
|
|
public async Task<IActionResult> EnableTFA()
|
|
{
|
|
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/DisableTFA
|
|
[HttpPost]
|
|
public async Task<IActionResult> DisableTFA()
|
|
{
|
|
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.
|
|
#if NET45
|
|
var code = await UserManager.GenerateChangePhoneNumberTokenAsync(await GetCurrentUserAsync(), phoneNumber);
|
|
ViewBag.Status = "For DEMO purposes only, the current code is " + code;
|
|
#endif
|
|
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 });
|
|
}
|
|
|
|
//
|
|
// 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
|
|
//});
|
|
//}
|
|
|
|
////
|
|
//// POST: /Manage/LinkLogin
|
|
//[HttpPost]
|
|
//[ValidateAntiForgeryToken]
|
|
//public IActionResult LinkLogin(string provider)
|
|
//{
|
|
// // Request a redirect to the external login provider to link a login for the current user
|
|
// return new AccountController.ChallengeResult(provider, Url.Action("LinkLoginCallback", "Manage"), User.Identity.GetUserId());
|
|
//}
|
|
|
|
////
|
|
//// GET: /Manage/LinkLoginCallback
|
|
//public async Task<ActionResult> LinkLoginCallback()
|
|
//{
|
|
// var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId());
|
|
// if (loginInfo == null)
|
|
// {
|
|
// return RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error });
|
|
// }
|
|
// var result = await UserManager.AddLoginAsync(User.Identity.GetUserId(), loginInfo.Login);
|
|
// return result.Succeeded ? RedirectToAction("ManageLogins") : RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error });
|
|
//}
|
|
|
|
#region Helpers
|
|
// Used for XSRF protection when adding external logins
|
|
//private const string XsrfKey = "XsrfId";
|
|
|
|
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
|
|
}
|
|
} |