| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451 |
- using Abp;
- using Abp.AspNetCore.Mvc.Authorization;
- using Abp.Configuration;
- using Abp.Configuration.Startup;
- using Abp.Domain.Uow;
- using Abp.Extensions;
- using Abp.Notifications;
- using Abp.Threading;
- using Abp.Timing;
- using Abp.UI;
- using Abp.Web.Models;
- using Abp.Zero.Configuration;
- using Microsoft.AspNetCore.Identity;
- using Microsoft.AspNetCore.Mvc;
- using System.Diagnostics;
- using System.Security.Claims;
- using Abp.Auditing;
- using VberAdmin.Authorization;
- using VberAdmin.Authorization.Users;
- using VberAdmin.Controllers;
- using VberAdmin.Identity;
- using VberAdmin.MultiTenancy;
- using VberAdmin.Web.Models.Account;
- using VberZero.AppService.Authorization;
- using VberZero.Authorization;
- using VberZero.Authorization.Users;
- using VberZero.BaseSystem.MultiTenancy;
- using VberZero.BaseSystem.Users;
- using VberZero.MultiTenancy;
- namespace VberAdmin.Web.Controllers;
- [DisableAuditing]
- public class AccountController : VberAdminControllerBase
- {
- private readonly UserManager _userManager;
- private readonly TenantManager _tenantManager;
- private readonly IMultiTenancyConfig _multiTenancyConfig;
- private readonly IUnitOfWorkManager _unitOfWorkManager;
- private readonly VzLoginResultTypeHelper _vzLoginResultTypeHelper;
- private readonly LogInManager _logInManager;
- private readonly SignInManager _signInManager;
- private readonly UserRegistrationManager _userRegistrationManager;
- private readonly ITenantCache _tenantCache;
- private readonly INotificationPublisher _notificationPublisher;
- public AccountController(
- UserManager userManager,
- IMultiTenancyConfig multiTenancyConfig,
- TenantManager tenantManager,
- IUnitOfWorkManager unitOfWorkManager,
- VzLoginResultTypeHelper vzLoginResultTypeHelper,
- LogInManager logInManager,
- SignInManager signInManager,
- UserRegistrationManager userRegistrationManager,
- ITenantCache tenantCache,
- INotificationPublisher notificationPublisher)
- {
- _userManager = userManager;
- _multiTenancyConfig = multiTenancyConfig;
- _tenantManager = tenantManager;
- _unitOfWorkManager = unitOfWorkManager;
- _vzLoginResultTypeHelper = vzLoginResultTypeHelper;
- _logInManager = logInManager;
- _signInManager = signInManager;
- _userRegistrationManager = userRegistrationManager;
- _tenantCache = tenantCache;
- _notificationPublisher = notificationPublisher;
- }
- #region Login / Logout
- public ActionResult Login(string userNameOrEmailAddress = "", string returnUrl = "", string successMessage = "")
- {
- if (string.IsNullOrWhiteSpace(returnUrl))
- {
- returnUrl = GetAppHomeUrl();
- }
- return View(new LoginFormViewModel
- {
- ReturnUrl = returnUrl,
- IsMultiTenancyEnabled = _multiTenancyConfig.IsEnabled,
- IsSelfRegistrationAllowed = IsSelfRegistrationEnabled(),
- MultiTenancySide = AbpSession.MultiTenancySide
- });
- }
- [HttpPost]
- [UnitOfWork]
- public virtual async Task<JsonResult> Login(LoginViewModel loginModel, string returnUrl = "", string returnUrlHash = "")
- {
- returnUrl = NormalizeReturnUrl(returnUrl);
- if (!string.IsNullOrWhiteSpace(returnUrlHash))
- {
- returnUrl = returnUrl + returnUrlHash;
- }
- var tenancyName = await _userManager.GetTenancyNameAsync(loginModel.UsernameOrEmailOrPhone);
- var loginResult = await GetLoginResultAsync(loginModel.UsernameOrEmailOrPhone, loginModel.Password, tenancyName);
- await _signInManager.SignInAsync(loginResult.Identity, loginModel.RememberMe);
- await UnitOfWorkManager.Current.SaveChangesAsync();
- return Json(new AjaxResponse { TargetUrl = returnUrl });
- }
- public async Task<ActionResult> Logout()
- {
- await _signInManager.SignOutAsync();
- return RedirectToAction("Login");
- }
- private async Task<AbpLoginResult> GetLoginResultAsync(string usernameOrEmailOrPhone, string password, string tenancyName)
- {
- var loginResult = await _logInManager.LoginAsync(usernameOrEmailOrPhone, password, tenancyName);
- switch (loginResult.Result)
- {
- case VzLoginResultType.Success:
- return loginResult;
- default:
- throw _vzLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(loginResult.Result, usernameOrEmailOrPhone, tenancyName);
- }
- }
- #endregion Login / Logout
- #region Register
- public ActionResult Register()
- {
- return RegisterView(new RegisterViewModel());
- }
- private ActionResult RegisterView(RegisterViewModel model)
- {
- ViewBag.IsMultiTenancyEnabled = _multiTenancyConfig.IsEnabled;
- return View("Register", model);
- }
- private bool IsSelfRegistrationEnabled()
- {
- if (!AbpSession.TenantId.HasValue)
- {
- return false; // No registration enabled for host users!
- }
- return true;
- }
- [HttpPost]
- [UnitOfWork]
- public async Task<ActionResult> Register(RegisterViewModel model)
- {
- try
- {
- ExternalLoginInfo externalLoginInfo = null;
- if (model.IsExternalLogin)
- {
- externalLoginInfo = await _signInManager.GetExternalLoginInfoAsync();
- if (externalLoginInfo == null)
- {
- throw new Exception("Can not external login!");
- }
- model.UserName = model.EmailAddress;
- model.Password = VberZero.BaseSystem.Users.User.CreateRandomPassword();
- }
- else
- {
- if (model.UserName.IsNullOrEmpty() || model.Password.IsNullOrEmpty())
- {
- throw new UserFriendlyException(L("FormIsNotValidMessage"));
- }
- }
- var user = await _userRegistrationManager.RegisterAsync(
- model.Name,
- model.Surname,
- model.EmailAddress,
- model.UserName,
- model.Password,
- true // Assumed email address is always confirmed. Change this if you want to implement email confirmation.
- );
- // Getting tenant-specific settings
- var isEmailConfirmationRequiredForLogin = await SettingManager.GetSettingValueAsync<bool>(AbpZeroSettingNames.UserManagement.IsEmailConfirmationRequiredForLogin);
- if (model.IsExternalLogin)
- {
- Debug.Assert(externalLoginInfo != null);
- if (string.Equals(externalLoginInfo.Principal.FindFirstValue(ClaimTypes.Email), model.EmailAddress, StringComparison.OrdinalIgnoreCase))
- {
- user.IsEmailConfirmed = true;
- }
- user.Logins = new List<UserLogin>
- {
- new UserLogin
- {
- LoginProvider = externalLoginInfo.LoginProvider,
- ProviderKey = externalLoginInfo.ProviderKey,
- TenantId = user.TenantId
- }
- };
- }
- await _unitOfWorkManager.Current.SaveChangesAsync();
- Debug.Assert(user.TenantId != null);
- var tenant = await _tenantManager.GetByIdAsync(user.TenantId.Value);
- // Directly login if possible
- if (user.IsActive && (user.IsEmailConfirmed || !isEmailConfirmationRequiredForLogin))
- {
- AbpLoginResult loginResult;
- if (externalLoginInfo != null)
- {
- loginResult = await _logInManager.LoginAsync(externalLoginInfo, tenant.TenancyName);
- }
- else
- {
- loginResult = await GetLoginResultAsync(user.UserName, model.Password, tenant.TenancyName);
- }
- if (loginResult.Result == VzLoginResultType.Success)
- {
- if (loginResult.Identity != null) await _signInManager.SignInAsync(loginResult.Identity, false);
- return Redirect(GetAppHomeUrl());
- }
- Logger.Warn("New registered user could not be login. This should not be normally. login result: " + loginResult.Result);
- }
- return View("RegisterResult", new RegisterResultViewModel
- {
- TenancyName = tenant.TenancyName,
- NameAndSurname = user.Name + " " + user.Surname,
- UserName = user.UserName,
- EmailAddress = user.EmailAddress,
- IsEmailConfirmed = user.IsEmailConfirmed,
- IsActive = user.IsActive,
- IsEmailConfirmationRequiredForLogin = isEmailConfirmationRequiredForLogin
- });
- }
- catch (UserFriendlyException ex)
- {
- ViewBag.ErrorMessage = ex.Message;
- return View("Register", model);
- }
- }
- #endregion Register
- #region External Login
- [HttpPost]
- [ValidateAntiForgeryToken]
- public ActionResult ExternalLogin(string provider, string returnUrl)
- {
- //var redirectUrl =
- Url.Action(
- "ExternalLoginCallback",
- "Account",
- new
- {
- ReturnUrl = returnUrl
- });
- return Challenge(
- // TODO: ...?
- // new Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties
- // {
- // Items = { { "LoginProvider", provider } },
- // RedirectUri = redirectUrl
- // },
- provider
- );
- }
- [UnitOfWork]
- public virtual async Task<ActionResult> ExternalLoginCallback(string returnUrl, string remoteError = null)
- {
- returnUrl = NormalizeReturnUrl(returnUrl);
- if (remoteError != null)
- {
- Logger.Error("Remote Error in ExternalLoginCallback: " + remoteError);
- throw new UserFriendlyException(L("CouldNotCompleteLoginOperation"));
- }
- var externalLoginInfo = await _signInManager.GetExternalLoginInfoAsync();
- if (externalLoginInfo == null)
- {
- Logger.Warn("Could not get information from external login.");
- return RedirectToAction(nameof(Login));
- }
- await _signInManager.SignOutAsync();
- var tenancyName = GetTenancyNameOrNull();
- var loginResult = await _logInManager.LoginAsync(externalLoginInfo, tenancyName);
- switch (loginResult.Result)
- {
- case VzLoginResultType.Success:
- await _signInManager.SignInAsync(loginResult.Identity, false);
- return Redirect(returnUrl);
- case VzLoginResultType.UnknownExternalLogin:
- return await RegisterForExternalLogin(externalLoginInfo);
- default:
- throw _vzLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(
- loginResult.Result,
- externalLoginInfo.Principal.FindFirstValue(ClaimTypes.Email) ?? externalLoginInfo.ProviderKey,
- tenancyName
- );
- }
- }
- private async Task<ActionResult> RegisterForExternalLogin(ExternalLoginInfo externalLoginInfo)
- {
- var email = externalLoginInfo.Principal.FindFirstValue(ClaimTypes.Email);
- var nameinfo = ExternalLoginInfoHelper.GetNameAndSurnameFromClaims(externalLoginInfo.Principal.Claims.ToList());
- var viewModel = new RegisterViewModel
- {
- EmailAddress = email,
- Name = nameinfo.name,
- Surname = nameinfo.surname,
- IsExternalLogin = true,
- ExternalLoginAuthSchema = externalLoginInfo.LoginProvider
- };
- if (nameinfo.name != null &&
- nameinfo.surname != null &&
- email != null)
- {
- return await Register(viewModel);
- }
- return RegisterView(viewModel);
- }
- [UnitOfWork]
- protected virtual async Task<List<Tenant>> FindPossibleTenantsOfUserAsync(UserLoginInfo login)
- {
- List<User> allUsers;
- using (_unitOfWorkManager.Current.DisableFilter(AbpDataFilters.MayHaveTenant))
- {
- allUsers = await _userManager.FindAllAsync(login);
- }
- return allUsers
- .Where(u => u.TenantId != null)
- .Select(u => AsyncHelper.RunSync(() => _tenantManager.FindByIdAsync(u.TenantId.Value)))
- .ToList();
- }
- #endregion External Login
- #region Helpers
- public ActionResult RedirectToAppHome()
- {
- return RedirectToAction("Index", "Home");
- }
- public string GetAppHomeUrl()
- {
- return Url.Action("Index", "Home");
- }
- #endregion Helpers
- #region Common
- private string GetTenancyNameOrNull()
- {
- if (!AbpSession.TenantId.HasValue)
- {
- return null;
- }
- return _tenantCache.GetOrNull(AbpSession.TenantId.Value)?.TenancyName;
- }
- private string NormalizeReturnUrl(string returnUrl, Func<string> defaultValueBuilder = null)
- {
- if (defaultValueBuilder == null)
- {
- defaultValueBuilder = GetAppHomeUrl;
- }
- if (returnUrl.IsNullOrEmpty())
- {
- return defaultValueBuilder();
- }
- if (Url.IsLocalUrl(returnUrl))
- {
- return returnUrl;
- }
- return defaultValueBuilder();
- }
- #endregion Common
- #region Etc
- /// <summary>
- /// This is a demo code to demonstrate sending notification to default tenant admin and host admin uers.
- /// Don't use this code in production !!!
- /// </summary>
- /// <param name="message"></param>
- /// <returns></returns>
- [AbpMvcAuthorize]
- public async Task<ActionResult> TestNotification(string message = "")
- {
- if (message.IsNullOrEmpty())
- {
- message = "This is a test notification, created at " + Clock.Now;
- }
- var defaultTenantAdmin = new UserIdentifier(1, 2);
- var hostAdmin = new UserIdentifier(null, 1);
- await _notificationPublisher.PublishAsync(
- "App.SimpleMessage",
- new MessageNotificationData(message),
- severity: NotificationSeverity.Info,
- userIds: new[] { defaultTenantAdmin, hostAdmin }
- );
- return Content("Sent notification: " + message);
- }
- #endregion Etc
- }
|