Creazione Account Controller
È in questo controller che si sviluppa tutta la magia della sicurezza!
L'Account controller contiene 9 Action Methods e un Costruttore. Di seguito riporto i nomi e gli scopi di tutti questi metodi:
Metodo |
Descrizione |
AccountController() |
Costruttore. Inizializza UserManager e RoleManager |
Register() |
ActionMethod. Ritorna la vista Register |
Register(Register model) |
Questa versione del metodo Register() viene chiamata quando l'utente invia la sottoscrizione e viene avviata la procedura di creazione dello user |
Login() |
ActionMethod. Ritorna la vista Login |
Login(Login model) |
Questa versione del metodo Login() viene chiamata quando l'utente invia la sottoscrizione e viene avviata la procedura di autenticazione dello user |
ChangePassword() |
ActionMethod. Ritorna la vista di ChangePassword |
ChangePassword(ChangePassword model) |
Questa versione del metodo ChangePassword() viene chiamata quando l'utente invia il Cambio di Password e viene avviata la procedura di modifica della password dello user |
ChangeProfile() |
ActionMethod. Ritorna la vista di ChangeProfile |
ChangeProfile(ChangeProfile model) |
Questa versione del metodo ChangeProfile() viene chiamata quando l'utente invia il Cambio di Profilo e viene avviata la procedura di modifica del profilo dello user |
Logout() |
Il metodo di Logout viene invocato quando un utente loggato preme sul pulsante Logout (da qualunauq View possa essere presente) e viene avviata la procedura di rimozione del cookie di autenticazione. |
Ora andiamo ad implementare questi metodi uno-per-uno.
Aggiungere la classe AccountController nella cartella Controllers e scrivere il costruttore:
private UserManager<MyIdentityUser> userManager;
private RoleManager<MyIdentityRole> roleManager;
public AccountController()
{
MyIdentityDbContext db = new MyIdentityDbContext();
UserStore<MyIdentityUser> userStore = new UserStore<MyIdentityUser>(db);
userManager = new UserManager<MyIdentityUser>(userStore);
RoleStore<MyIdentityRole> roleStore = new RoleStore<MyIdentityRole>(db);
roleManager = new RoleManager<MyIdentityRole>(roleStore);
}
Il codice precedente dichiara due variabili all'interno della classe AccountController - una di tipo UserManager ed una di tipo RoleManager. Mentre vengono dichiarate queste variabili, vengono specificati i tipi generici di MyIdentityUser e MyIdentityRole.
Il costruttore della classe AccountController crea un'istanza del DbContext personalizzato e lo passa al costruttore delle classi UserStore e RoleStore: queste istanze vengono passate successivamente al costruttore delle classi UserManager e RoleManager. Le classi UserStore e RoleStore fondamentalmente si occupano di archiviare e recuperare i dati dal database.
public ActionResult Register()
{
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Register(Register model)
{
if (ModelState.IsValid)
{
MyIdentityUser user = new MyIdentityUser();
user.UserName = model.UserName;
user.Email = model.Email;
user.FullName = model.FullName;
user.BirthDate = model.BirthDate;
user.Bio = model.Bio;
IdentityResult result = userManager.Create(user, model.Password);
if (result.Succeeded)
{
userManager.AddToRole(user.Id, "Administrator");
return RedirectToAction("Login","Account");
}
else
{
ModelState.AddModelError("UserName", "Error while creating the user!");
}
}
return View(model);
}
La versione POST del metodo Register() crea un'istanza della classe MyIdentityUser e setta le sue proprietà alle corrispondenti proprietà della classe Modello Register. Dopodiché viene creato un nuovo User Account chiamando il metodo Create() dall'oggetto UserManager.
Se IdentityResult.Succeded ritorna TRUE, indica che è stato correttamente creato un User Account, in questo modo il nuovo utente appena creato viene assegnato il ruolo di Amministratore (in una situazione più reale, si dovrà separare la gestione dei ruoli dell'utente in una pagina diversa, per assegnare un nuovo ruolo all'utente, qui per maggiore semplicità, viene assegnato un ruolo nel medesimo istante in cui viene creato). L'utente viene quindi reindirizzato alla pagina di Login.
Se viene sollevato qualche errore durante la creazione dell'User, un messaggio di errore viene aggiunto al Dictionary ModelState e la View Register viene nuovamente mostrata con il messaggio di errore.
public ActionResult Login(string returnUrl)
{
ViewBag.ReturnUrl = returnUrl;
return View();
}
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult Login(Login model, string returnUrl)
{
if (ModelState.IsValid)
{
MyIdentityUser user = userManager.Find(model.UserName, model.Password);
if (user != null)
{
IAuthenticationManager authMgr = HttpContext.GetOwinContext().Authentication;
authMgr.SignOut(DefaultAuthenticationType.ExternalCookie);
ClaimsIdentity identity = userMgr.CreateIdentity(user, DefaultAuthenticationType.ApplicationCookie);
AuthenticationProperties props = new AuthenticationProperties();
props.IsPersistent = model.RememberMe;
authMgr.SignIn(props, identity);
if (Url.IsLocalUrl(returnUrl))
return Redirect(returnUrl);
else
return RedirectToAction("Index", "Home");
}
else
ModelState.AddModelError("", "UserName o Password non validi");
}
return View(model);
}
Se un utente tenta di effettuare l'accesso senza loggarsi, viene automaticamente re-indirizzato alla pagina di Login. Nel fare questa operazione, il sistema passa come parametro l'url della pagina richiesta come parametro stringa. Questo parametro viene recuperato dal metodo Login(). Il primo metodo Login() semplicemente passa il parametro returnUrl alla View perché possa essere reinviato al termine dell'operazione di Login.
Il secondo metodo Login() effettua la validazione di UserName e Password se sono corretti: questa procedura è fatta effettuando la ricerca di un utente con specifico UserName e Password utilizzando l'oggetto UserManager. Se viene trovato un utente con i parametri corretti, la procedura riceve un AuthenticationManager chiamando HttpContext.GetOwinContext().Authentication ed archivia in una variabile di tipo IAuthenticationManager. L'utente si può sloggare chiamando il metodo SignOut(). Infine l'oggetto ClaimsIdentity viene creato chiamando il metodo CreateIdentity() dall'UserManager. Il metodo SignIn() accetta questo ClaimsIdentity ed effettua le operazioni di autenticazione. L'oggetto AuthenticationProperties specifica la proprietà IsPersistent per indicare se i cookie di autenticazione devono essere persistenti(true) o no(false).
[Authorize]
public ActionResult ChangePassword()
{
return View();
}
[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public ActionResult ChangePassword(ChangePassword model)
{
if (ModelState.IsValid)
{
MyIdentityUser user = userManager.FindByName(HttpContext.User.Identity.Name);
IdentityResult result = userManager.ChangePassword(user.Id, model.OldPassword, model.NewPassword);
if (result.Succeded)
{
IAuthenticationManager authMgr = HttpContext.GetOwinContext().Authentication;
authMgr.SignOut();
return RedirectToAction("Login", "Account");
}
else
ModelState.AddModelError("", "Errore nel cambio di Password");
}
return View(model);
}
Il secondo metodo ChangePassword() riceve lo UserName corrente mediante HttpContext.User.Identity.Name; grazie a questo valore, il metodo FindByName() di UserManager ritorna il MyIdentityUser associato. Infine il metodo ChangePassword() di UserManager passando l'Id dell'utente, la vecchia password e la nuova password. Se l'operazione viene eseguita con successo, l'utente viene sloggato ed il sistema lo reindirizza alla pagina di Login.
[Authorize]
public ActionResult ChangeProfile()
{
MyIdentityUser user = userManager.FindByName(HttpContext.User.Identity.Name);
ChangeProfile model = new ChangeProfile();
model.FullName = user.FullName;
model.BirthDate = user.BirthDate;
model.Bio = user.Bio;
return View(model);
}
[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public ActionResult ChangeProfile()
{
if (ModelState.IsValid)
{
MyIdentityUser user = userManager.FindByName(HttpContext.User.Identity.Name);
user.FullName = model.FullName;
user.BirthDate = model.BirthDate;
user.Bio = model.Bio;
IdentityResult result = userManager.Update(user);
if (result.Succeded)
ViewBag.Message = "Profilo aggiornato correttamente"
else
ModelState.AddModelError("", "Errore nel salvataggio del profilo");
{
return View(model);
}
Il primo metodo ChangeProfile() recupera MyIdentityUser mediante il metodo FindByName() di UserManager. I dettagli del profilo dell'utente corrente servono per riempire i campi del Model ChangeProfile e passati alla View ChangeProfile. Il secondo metodo ChangeProfile() riceve le informazioni modificate e mediante il metodo Update() aggiorna il profilo recuperato mediante il metodo FindByName() di UserManager.
[HttpPost]
[Authorize]
[ValidateAntiForgeryToken]
public ActionResult LogOut()
{
IAuthenticationManager authMgr = HttpContext.GetOwinContext().Autentication;;
authMgr.SignOut();
return RedirectToAction("Login", "Account");
}
|