I want to redirect the URL after authentication in multi-tenant application.
When user enters credentials on login page(URL: domain_name.com) and after successful authentication, browser URL must changed to {tenancy_name}.domain_name.com
I got tenancy name using email address and password. Now, I want to put that tenancy name into browser URL to get it identified for user.
This is a case when user forgot to put tenancy name in URL means user enters URL like: domain_name.com
Then after successful authentication, tenancy name must be added to URL like:
{tenancy_name}.domain_name.com
And must redirect to the dashboard page.
Following is my Login post method:
HttpPost
UnitOfWork
public virtual async Task<ActionResult> Login(LoginViewModel loginModel, int paymentFlag, string returnUrl = "", string returnUrlHash = "")
{
try
{
var tenant = await _tenantManager.FindByTenancyNameAsync(loginModel.TenancyName);
if (tenant.IsActive == true)
{
if (tenant != null)
{
var payments = await _paymentRepository.GetAll().Where(p => p.TenantId == tenant.Id).FirstOrDefaultAsync();
if (paymentFlag == 0)
{
if (payments == null)
{
return RedirectToAction("Payment", loginModel);
}
}
}
var loginResult = await GetLoginResultAsync(loginModel.UsernameOrEmailAddress, loginModel.Password, loginModel.TenancyName);
var tenantId = loginResult.Tenant == null ? (int?)null : loginResult.Tenant.Id;
using (UnitOfWorkManager.Current.SetTenantId(tenantId))
{
if (loginResult.User.ShouldChangePasswordOnNextLogin)
{
loginResult.User.SetNewPasswordResetCode();
return RedirectToAction("ResetPassword", new
{
TenantId = SimpleStringCipher.Instance.Encrypt(tenantId == null ? null : tenantId.ToString()),
UserId = SimpleStringCipher.Instance.Encrypt(loginResult.User.Id.ToString()),
ResetCode = loginResult.User.PasswordResetCode
});
}
var signInResult = await _signInManager.SignInOrTwoFactorAsync(loginResult, loginModel.RememberMe);
if (signInResult == SignInStatus.RequiresVerification)
{
return RedirectToAction("SendSecurityCode", new
{
returnUrl = returnUrl + (returnUrlHash ?? ""),
rememberMe = loginModel.RememberMe
});
}
Debug.Assert(signInResult == SignInStatus.Success);
await UnitOfWorkManager.Current.SaveChangesAsync();
if (string.IsNullOrWhiteSpace(returnUrl))
{
returnUrl = GetAppHomeUrl();
}
if (!string.IsNullOrWhiteSpace(returnUrlHash))
{
returnUrl = returnUrl + returnUrlHash;
}
}
}
else
{
throw new UserFriendlyException(L("UserEmailIsNotConfirmedAndCanNotLogin"));
}
}
catch (UserFriendlyException ex)
{
return RedirectToAction("Login", new
{
errorMessage = ex.Message
});
}
return Json(new AjaxResponse { TargetUrl = returnUrl });
}
,
I found a simple solution. Update app-initializer.ts
as follows:
First, add method
private replaceTenantPlaceholder(baseUrl: string, defaultSubDomain: string): string {
const tenancyNamePlaceHolder = '{TENANCY_NAME}';
baseUrl = baseUrl.replace(tenancyNamePlaceHolder + '.', tenancyNamePlaceHolder);
var subDomain = window.location.hostname.split(".")0;
subDomain = subDomain.replace(`$:{window.location.port}`, "");
switch (window.location.hostname.split(".").length) {
case 1:
case 2:
//No sub-domain on current url
subDomain = defaultSubDomain;
if (subDomain.length > 0) subDomain += ".";
break;
case 3:
//Use the current url's sub-domain
subDomain += ".";
default:
}
return baseUrl.replace(tenancyNamePlaceHolder, subDomain);
}
Then update method getApplicationConfig
:
AppConsts.appBaseUrl = this.replaceTenantPlaceholder(response.appBaseUrl, "www");
AppConsts.remoteServiceBaseUrl = this.replaceTenantPlaceholder(response.remoteServiceBaseUrl, "");
No other modifications needed for this part of the multi-tenancy. Make sure you update your Configuration.Modules.AbpWebCommon().MultiTenancy.DomainFormat
in your CoreModule and define your CorsOrigins in appsettings.json
My client application requires “www” in the domain, so that is why I have the defaultSubDomain parameter. You can omit that if not needed.