using System;
using System.Globalization;
using System.Threading.Tasks;
using gehGassi.Core.Interfaces;
using gehGassi.Domain.Users;
using gehGassi.Web.Auth;
using gehGassi.Web.Helper;
using gehGassi.Web.Models;
using gehGassi.Web.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Localization;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
namespace gehGassi.Web.Controllers
{
///
/// Controller für die Verwaltung von Logins, Logouts usw.
///
[Authorize]
public class AccountController : BaseController
{
private readonly SignInManager _signInManager;
private readonly ILogger _logger;
private readonly IStringLocalizer _localizer;
private readonly IEmailSender _emailSender;
private readonly IUserService _userService;
private readonly IOptions _licenseOptions;
private readonly UserManager _userManager;
private readonly IOptions _sessionSettings;
///
/// Erstellt eine Istanz
///
/// Instanz eines SignInManager
/// Instanz eines ILogger
/// Instanz eines IStringLocalizer
/// Instanz eines IEmailSender
/// Isntanz eines IUserService
/// Instanz eines IOptions LicenseOptions
/// Instanz eines UserManager
/// Instanz eines IOptions SessionSettings
public AccountController(SignInManager signInManager, ILogger logger, IStringLocalizer localizer,
IEmailSender emailSender, IUserService userService, IOptions licenseOptions, UserManager userManager,
IOptions sessionSettings)
{
_signInManager = signInManager;
_logger = logger;
_localizer = localizer;
_emailSender = emailSender;
_userService = userService;
_licenseOptions = licenseOptions;
_userManager = userManager;
_sessionSettings = sessionSettings;
}
///
/// Zeigt eine View zur Anmeldung an
///
/// Optional: Return URL
/// View
[AllowAnonymous]
public IActionResult Login(string returnUrl)
{
var model = new LoginVm();
#if DEBUG
//model.UserName = "office@creativebits.com";
//model.Password = "!eLearningFox#321";
#endif
ViewBag.ReturnUrl = returnUrl;
return View(model);
}
///
/// Login
///
/// Benutzerdaten
/// Optional: ReturnUrl
/// Redirect oder View
[AllowAnonymous]
[HttpPost]
[ValidateAntiForgeryToken]
public async Task Login(LoginVm model, string returnUrl)
{
if (ModelState.IsValid)
{
//Hundebesitzer und hundeausführer düfen nicht in das Backend.
//Ausser es sind Admins oder Poweruser mit Test-Rollen
var userCheck = await _signInManager.UserManager.FindByNameAsync(model.UserName);
if (userCheck != null)
{
var roles = await _userManager.GetRolesAsync(userCheck);
if (!roles.Contains("Administrator"))
{
if (!roles.Contains("PowerUser"))
{
if (roles.Contains("DogOwner") || roles.Contains("DogWalker"))
{
return Redirect("https://gehgassi.com");
}
}
}
}
var result = await _signInManager.PasswordSignInAsync(model.UserName, model.Password, _sessionSettings.Value.PersistentCookie, lockoutOnFailure: true);
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
var user = await _userService.GetByUsernameAsync(model.UserName);
user.LastLoginDate = DateTimeOffset.UtcNow;
await _userService.CommitAsync(user.UserName);
var roles = await _userManager.GetRolesAsync(user);
CultureInfo.CurrentCulture = new CultureInfo(user.PreferredLanguage);
if (roles.Contains("Administrator"))
return RedirectToAction("Index", "Home", new { culture = CultureInfo.CurrentCulture.TwoLetterISOLanguageName });
if (roles.Contains("PowerUser"))
return RedirectToAction("Index", "Home", new { culture = CultureInfo.CurrentCulture.TwoLetterISOLanguageName });
else if (roles.Contains("Customer"))
return RedirectToAction("IndexCustomer", "Home", new { culture = CultureInfo.CurrentCulture.TwoLetterISOLanguageName });
else if (roles.Contains("AppUser"))
{
await _signInManager.SignOutAsync();
return RedirectToAction("Login", "Account", new { culture = CultureInfo.CurrentCulture.TwoLetterISOLanguageName });
//return RedirectToAction("IndexAppUser", "Home", new { culture = CultureInfo.CurrentCulture.TwoLetterISOLanguageName });
}
else if (roles.Contains("ApiUser"))
{
await _signInManager.SignOutAsync();
return RedirectToAction("Login", "Account", new { culture = CultureInfo.CurrentCulture.TwoLetterISOLanguageName });
}
else
return RedirectToAction("Status401", "Home", new { culture = CultureInfo.CurrentCulture.TwoLetterISOLanguageName });
}
if (result.RequiresTwoFactor)
{
return RedirectToAction("VerifyAuthenticatorCode");
}
if (result.IsLockedOut)
{
_logger.LogWarning("User account locked out.");
return RedirectToAction("Lockout");
}
else
{
//Prüfen ob die Email-Adresse noch nicht bestätigt wurde....
bool errorAdded = false;
var user = await _userManager.FindByEmailAsync(model.UserName);
if (user != null)
{
if (await _userManager.IsEmailConfirmedAsync(user) == false)
{
ModelState.AddModelError(string.Empty, _localizer["Err_Login_EmailNotConfirmed"]);
ViewBag.ShowEmailConfirmation = true;
errorAdded = true;
}
}
if (!errorAdded)
ModelState.AddModelError(string.Empty, _localizer["Err_Login_Invalid"]);
}
}
ViewBag.ReturnUrl = returnUrl;
return View(model);
}
///
/// Abmelden eines Benutzers
///
/// Redirect
[HttpPost]
[ValidateAntiForgeryToken]
public async Task Logout()
{
await _signInManager.SignOutAsync();
_logger.LogInformation("User logged out.");
return RedirectToAction("Login", "Account", new { culture = CultureInfo.CurrentCulture.TwoLetterISOLanguageName });
}
///
/// Zeigt eine View an die über eine Sperre informiert
///
/// View
[AllowAnonymous]
public IActionResult Lockout()
{
var timeLockedInMinutes = (int)_signInManager.Options.Lockout.DefaultLockoutTimeSpan.TotalMinutes;
return View(timeLockedInMinutes);
}
///
/// Zeigt eine View für Passwort-Vergessen an
///
/// View
[HttpGet]
[AllowAnonymous]
public IActionResult ForgotPassword()
{
return View();
}
///
/// Handling für Passwort Vergessen
///
/// Benutzereingaben
/// Redirect oder View
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task ForgotPassword(ForgotPasswordVm model)
{
if (ModelState.IsValid)
{
try
{
var user = await _signInManager.UserManager.FindByNameAsync(model.Email);
if (user != null && (await _signInManager.UserManager.IsEmailConfirmedAsync(user)))
{
var token = await _signInManager.UserManager.GeneratePasswordResetTokenAsync(user);
var callbackUrl = Url.ResetPasswordCallbackLink(user.Id, token, Request.Scheme);
await _emailSender.SendPasswordResetAsync(model.Email, callbackUrl, _localizer, _licenseOptions);
}
}
catch { }
return RedirectToAction(nameof(ForgotPasswordConfirmation));
}
// If we got this far, something failed, redisplay form
return View(model);
}
///
/// Zeigt die Bestätigung für Passwort vergessen an
///
/// View
[HttpGet]
[AllowAnonymous]
public IActionResult ForgotPasswordConfirmation()
{
return View();
}
///
/// Zeigt eine View zum Zurücksetzen des Passwortes an
///
/// Rücksetzcode
/// View
[HttpGet]
[AllowAnonymous]
public IActionResult ResetPassword(string code = null)
{
if (code == null)
{
throw new ApplicationException("A code must be supplied for password reset.");
}
var model = new ResetPasswordVm() { Code = code };
return View(model);
}
///
/// Zurücksetzen des Passwortes eines Benutzers
///
/// Benutzereingaben
///
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task ResetPassword(ResetPasswordVm model)
{
if (!ModelState.IsValid)
{
return View(model);
}
if (await _userService.IsUsernameAvailableAsync(model.Email))
{
// Don't reveal that the user does not exist
return RedirectToAction(nameof(ResetPasswordConfirmation));
}
try
{
var user = await _signInManager.UserManager.FindByNameAsync(model.Email);
if (user != null)
{
var result = await _signInManager.UserManager.ResetPasswordAsync(user, model.Code, model.Password);
if (result.Succeeded)
{
return RedirectToAction(nameof(ResetPasswordConfirmation));
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
}
catch { }
return View(model);
}
///
/// Anzeigen eines Erfolgs-Views für das Zurücksetzen eines Passwortes
///
///
[HttpGet]
[AllowAnonymous]
public IActionResult ResetPasswordConfirmation()
{
return View();
}
#region Reset Password für API
///
/// Zeigt eine View zum Zurücksetzen des Passwortes an
///
/// Rücksetzcode
/// View
[HttpGet]
[AllowAnonymous]
public IActionResult ResetPasswordApp(string code = null)
{
if (code == null)
{
throw new ApplicationException("A code must be supplied for password reset.");
}
var model = new ResetPasswordVm() { Code = code };
return View(model);
}
///
/// Zurücksetzen des Passwortes eines Benutzers
///
/// Benutzereingaben
///
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task ResetPasswordApp(ResetPasswordVm model)
{
if (!ModelState.IsValid)
{
return View(model);
}
if (await _userService.IsUsernameAvailableAsync(model.Email))
{
// Don't reveal that the user does not exist
return RedirectToAction(nameof(ResetPasswordConfirmationApp));
}
try
{
var user = await _signInManager.UserManager.FindByNameAsync(model.Email);
if (user != null)
{
var result = await _signInManager.UserManager.ResetPasswordAsync(user, model.Code, model.Password);
if (result.Succeeded)
{
return RedirectToAction(nameof(ResetPasswordConfirmationApp));
}
foreach (var error in result.Errors)
{
ModelState.AddModelError(string.Empty, error.Description);
}
}
}
catch { }
return View(model);
}
///
/// Anzeigen eines Erfolgs-Views für das Zurücksetzen eines Passwortes
///
///
[HttpGet]
[AllowAnonymous]
public IActionResult ResetPasswordConfirmationApp()
{
return View();
}
#endregion
[HttpGet]
[AllowAnonymous]
public IActionResult AccessDenied(string returnUrl)
{
return View();
}
///
/// Anzeige der email-Bestätigung der Email-Adresse
///
///
///
///
[HttpGet]
[AllowAnonymous]
public async Task ConfirmEmail(string userId, string code)
{
var model = new LoginVm();
if (userId == null || code == null)
{
ViewBag.ShowEmailConfirmation = true;
ModelState.AddModelError(string.Empty, _localizer["Common_ConfirmEmailFailed_Desc"]);
return View("Login", model);
}
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
ViewBag.ShowEmailConfirmation = true;
ModelState.AddModelError(string.Empty, _localizer["Common_ConfirmEmailFailed_Desc"]);
return View("Login", model);
}
var result = await _userManager.ConfirmEmailAsync(user, code);
if (!result.Succeeded)
{
ViewBag.ShowEmailConfirmation = true;
ModelState.AddModelError(string.Empty, _localizer["Common_ConfirmEmailFailed_Desc"]);
return View("Login", model);
}
ViewBag.ShowEmailConfirmationSuccess = true;
return View("Login", model);
}
///
/// Anzeige der email-Bestätigung der Email-Adresse für die App
///
///
///
///
[HttpGet]
[AllowAnonymous]
public async Task ConfirmEmailApp(string userId, string code)
{
var model = _localizer["Common_ConfirmEmail_Success"].Value;
if (userId == null || code == null)
{
model = _localizer["Common_ConfirmEmailFailed_Desc"].Value;
}
var user = await _userManager.FindByIdAsync(userId);
if (user == null)
{
model = _localizer["Common_ConfirmEmailFailed_Desc"].Value;
}
var result = await _userManager.ConfirmEmailAsync(user, code);
if (!result.Succeeded)
{
model = _localizer["Common_ConfirmEmailFailed_Desc"].Value;
}
return View("ConfirmEmailApp", model);
}
///
/// Zeigt eine View für das erneute Senden des Email-Bestätigungscodes an
///
/// View
[HttpGet]
[AllowAnonymous]
public IActionResult SendEmailConfirmation()
{
return View();
}
///
/// Handling für Email-Bestätigung neu senden
///
/// Benutzereingaben
/// Redirect oder View
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task SendEmailConfirmation(ForgotPasswordVm model)
{
if (ModelState.IsValid)
{
try
{
var user = await _signInManager.UserManager.FindByNameAsync(model.Email);
if (user != null && (await _signInManager.UserManager.IsEmailConfirmedAsync(user)) == false)
{
var code = await _signInManager.UserManager.GenerateEmailConfirmationTokenAsync(user);
var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code = code }, protocol: HttpContext.Request.Scheme);
await _emailSender.SendEmailConfirmationAsync(user.UserName, callbackUrl, _localizer, LicenseOptions);
}
}
catch { }
return RedirectToAction(nameof(SendEmailConfirmationDone));
}
// If we got this far, something failed, redisplay form
return View(model);
}
///
/// Zeigt die Bestätigung für das erneute Senden des Email-Bestätigungscodes an
///
/// View
[HttpGet]
[AllowAnonymous]
public IActionResult SendEmailConfirmationDone()
{
return View();
}
///
/// View für den 2 Faktor Auth-Code
///
/// View
[HttpGet]
[AllowAnonymous]
public async Task VerifyAuthenticatorCode()
{
// Require that the user has already logged in via username/password or external login
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
if (user == null)
{
return View("Error");
}
return View(new VerifyAuthenticatorCodeViewModel());
}
///
/// View für den 2 Faktor Auth-Code
///
/// View
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task VerifyAuthenticatorCode(VerifyAuthenticatorCodeViewModel 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.
var result = await _signInManager.TwoFactorAuthenticatorSignInAsync(model.Code, false, false);
if (result.Succeeded)
{
_logger.LogInformation("User logged in.");
var user = await _signInManager.GetTwoFactorAuthenticationUserAsync();
user.LastLoginDate = DateTimeOffset.UtcNow;
await _userService.CommitAsync(user.UserName);
var roles = await _userManager.GetRolesAsync(user);
CultureInfo.CurrentCulture = new CultureInfo(user.PreferredLanguage);
if (roles.Contains("Administrator"))
return RedirectToAction("Index", "Home", new { culture = CultureInfo.CurrentCulture.TwoLetterISOLanguageName });
if (roles.Contains("PowerUser"))
return RedirectToAction("Index", "Home", new { culture = CultureInfo.CurrentCulture.TwoLetterISOLanguageName });
else if (roles.Contains("Customer"))
return RedirectToAction("IndexCustomer", "Home", new { culture = CultureInfo.CurrentCulture.TwoLetterISOLanguageName });
else if (roles.Contains("AppUser"))
return RedirectToAction("IndexAppUser", "Home", new { culture = CultureInfo.CurrentCulture.TwoLetterISOLanguageName });
else
return RedirectToAction("Status401", "Home", new { culture = CultureInfo.CurrentCulture.TwoLetterISOLanguageName });
}
if (result.IsLockedOut)
{
return View("Lockout");
}
else
{
ModelState.AddModelError("Code", _localizer["Err_Invalid_Code"]);
return View(model);
}
}
}
}