aspnetcore/samples/IdentitySample.Mvc/Controllers/ManageController.cs

398 lines
14 KiB
C#

using IdentitySample.Models;
using Microsoft.AspNet.Http;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Mvc;
using System.Linq;
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
[HttpGet]
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.IsTwoFactorClientRememberedAsync(user)
};
return View(model);
}
//
// GET: /Account/RemoveLogin
[HttpGet]
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, 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/RememberBrowser
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> RememberBrowser()
{
var user = await GetCurrentUserAsync();
if (user != null)
{
await SignInManager.RememberTwoFactorClientAsync(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");
}
//
// POST: /Manage/EnableTFA
[HttpPost]
[ValidateAntiForgeryToken]
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]
[ValidateAntiForgeryToken]
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
[HttpGet]
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
[HttpGet]
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
[HttpGet]
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
[HttpGet]
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
[HttpGet]
public async Task<IActionResult> ManageLogins(ManageMessageId? message = null)
{
ViewBag.StatusMessage =
message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
: message == ManageMessageId.AddLoginSuccess ? "The external login was added."
: 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 = Context.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
var redirectUrl = Url.Action("LinkLoginCallback", "Manage");
var properties = Context.ConfigureExternalAuthenticationProperties(provider, redirectUrl, User.Identity.GetUserId());
return new ChallengeResult(provider, properties);
}
//
// GET: /Manage/LinkLoginCallback
[HttpGet]
public async Task<ActionResult> LinkLoginCallback()
{
var user = await GetCurrentUserAsync();
if (user == null)
{
return View("Error");
}
var info = await Context.GetExternalLoginInfo(User.Identity.GetUserId());
if (info == null)
{
return RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error });
}
var result = await UserManager.AddLoginAsync(user, info);
var message = result.Succeeded ? ManageMessageId.AddLoginSuccess : ManageMessageId.Error;
return RedirectToAction("ManageLogins", new { Message = message });
}
#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,
AddLoginSuccess,
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
}
}