- Template: microservice
- Created ABP Studio Version: 2.1.3
- Current ABP Studio Version: 2.1.3
- Multi-Tenancy: Yes
- UI Framework: angular
- Theme: leptonx
- Theme Style: system
- Theme Menu Placement: side
- Run Install Libs: No
- Database Provider: ef
- Database Management System: postgresql
- Mobile Framework: none
- Public Website: No
- Social Login: No
- Include Tests: Yes
- Dynamic Localization: Yes
- Kubernetes Configuration: Yes
- Grafana Dashboard: Yes
- Use Local References: No
- Aspire: No
- Optional Modules:
- FileManagement
- TextTemplateManagement
- OpenIddictAdmin
- Selected Languages: Tiįŗæng Viį»t, English
- Default Language: Tiįŗæng Viį»t
- Create Command: abp new kcb -t microservice --ui-framework angular --database-provider ef --database-management-system postgresql --theme leptonx --skip-migration --skip-migrator --without-cms-kit --dont-run-install-libs --dont-run-bundling --no-social-logins -no-gdpr -no-audit-logging -no-language-management -file-management
Hello, I would like the login form to include three textbox fields: Tenant Name, Username, and Password. The customer requires that no switch button be used. Could you please guide me on how I can accomplish this? Thank you very much
6 Answer(s)
-
0
- Solution To have three textboxes on the login page (Tenant name, Username, Password) and remove the tenant switch button for an Angular UI with LeptonX theme and multi-tenancy enabled, do the following:
A) Remove the tenant switch UI on the Account layout (server-side) for LeptonX
- Create a view override to remove the built-in tenant switcher that appears on the public Account pages (Login, etc.).
- In your AuthServer (or Public Web, depending on template), add this file with the same path to override the themeās layout:
- Path: Themes/LeptonX/Layouts/Account/Default.cshtml
- Copy the original content from the LeptonX Account layout and remove (or comment out) the block that renders the tenant switch:
- The block guarded by: if (MultiTenancyOptions.Value.IsEnabled && (TenantResolveResultAccessor.Result?.AppliedResolvers?.Contains(CookieTenantResolveContributor.ContributorName) == true || TenantResolveResultAccessor.Result?.AppliedResolvers?.Contains(QueryStringTenantResolveContributor.ContributorName) == true))
- Delete that entire block (including the link with id="AbpTenantSwitchLink").
- This ensures no switch button is shown on the login page.
B) Add a Tenant Name textbox to the Angular login component and send it with the login request
- In the Angular application (apps/angular), extend the login form to include a Tenant Name field and set the tenant header (__tenant) programmatically. ABP Angular sends the current tenant on each request from the application-configuration result. Since you need a textbox on the login form, set the tenant before calling the login API.
Example steps:
Create a form control and UI for tenant input:
- If you are using the out-of-the-box LoginComponent from @abp/ng.account (Public), create a custom login component (or extend the existing one by wrapping it) that:
- Adds a tenantName: FormControl to the form.
- Renders a textbox above Username and Password.
- If you are using the out-of-the-box LoginComponent from @abp/ng.account (Public), create a custom login component (or extend the existing one by wrapping it) that:
Set the tenant header before login:
- Inject RestService or use ABP Angularās tenant setter by writing the selected tenant name to the cookie/header before invoking login.
- For Angular, ABP resolves tenant from:
- __tenant header, or
- abp.tenant cookie, or
- query string (__tenant)
- For a simple approach, set the abp.tenant cookie from the textbox value just before calling login; ABPās standard backend resolves it.
Example (illustrative, place inside your custom login component):
import { Component, inject } from '@angular/core'; import { FormBuilder, Validators } from '@angular/forms'; import { RestService } from '@abp/ng.core'; import { AccountService } from '@abp/ng.account/public/config'; // or your own auth call @Component({ selector: 'app-custom-login', template: ` <form [formGroup]="form" (ngSubmit)="login()"> <label>Tenant Name</label> <input formControlName="tenantName" type="text" autocomplete="organization" /> <label>Username</label> <input formControlName="username" type="text" autocomplete="username" /> <label>Password</label> <input formControlName="password" type="password" autocomplete="current-password" /> <button type="submit" [disabled]="form.invalid || submitting">Login</button> </form> ` }) export class CustomLoginComponent { private fb = inject(FormBuilder); private rest = inject(RestService); private account = inject(AccountService); // if you use the ABP Account endpoints submitting = false; form = this.fb.group({ tenantName: [''], username: ['', Validators.required], password: ['', Validators.required], rememberMe: [false], }); private setTenantCookie(name: string | null | undefined) { // When empty, clear cookie; when not empty, set cookie. const cookieName = 'abp.tenant'; const encoded = name ? encodeURIComponent(name) : ''; const expires = new Date(); expires.setDate(expires.getDate() + 30); if (encoded) { document.cookie = `${cookieName}=${encoded}; path=/; expires=${expires.toUTCString()}; SameSite=Lax`; } else { // clear document.cookie = `${cookieName}=; path=/; expires=Thu, 01 Jan 1970 00:00:00 GMT; SameSite=Lax`; } } async login() { if (this.form.invalid) return; this.submitting = true; try { const tenantName = (this.form.value.tenantName || '').trim(); // Ensure the backend resolves the request under this tenant: this.setTenantCookie(tenantName || null); // If you call login via a custom HTTP request, you can also set __tenant header: // Example: // await this.rest.request({ // method: 'POST', // url: '/api/account/login', // body: { userName: this.form.value.username, password: this.form.value.password }, // headers: tenantName ? { __tenant: tenantName } : {} // }).toPromise(); // If using ABP AccountService (OIDC flow), just trigger sign-in flow after setting cookie await this.account.navigateToLogin(); // or start the flow used in your app } finally { this.submitting = false; } } }Notes:
- If you use the standard OIDC login redirection provided by the Account Public module (AuthServer), setting abp.tenant cookie before starting the login is enough for the server to pick the correct tenant.
- If you are calling a username/password endpoint directly, add the __tenant header to that request instead of (or in addition to) the cookie.
C) Ensure tenant resolution is configured to accept cookie/header
- ABPās default multi-tenancy supports cookie and header resolvers. By default, Angular UI sends __tenant. If you rely on the cookie, ensure the CookieTenantResolveContributor is active (it is by default). If you previously customized AbpTenantResolveOptions to remove resolvers, re-include CookieTenantResolveContributor or HeaderTenantResolveContributor.
Example to ensure defaults (in your HttpApiHostModule or AuthServer):
using Volo.Abp.MultiTenancy; public override void ConfigureServices(ServiceConfigurationContext context) { Configure<AbpTenantResolveOptions>(options => { // Keep default resolvers, or ensure header/cookie are present // options.TenantResolvers.Clear(); // options.TenantResolvers.Add(new HeaderTenantResolveContributor()); // options.TenantResolvers.Add(new CookieTenantResolveContributor()); // options.TenantResolvers.Add(new QueryStringTenantResolveContributor()); }); }Outcome
- Login page shows three textboxes: Tenant Name, Username, Password.
- No tenant switch button is available on the page.
- The chosen tenant is applied for the login request via cookie or header consistently with ABP multi-tenancy.
- Sources
- https://abp.io/docs/latest/framework/ui/angular/multi-tenancy
- https://abp.io/docs/latest/framework/architecture/multi-tenancy#host-or-tenant
- https://abp.io/support/questions/9283
This response was generated by AI. If it didnāt solve your problem, feel free to post a new answer ā our support team will jump in to help you soon.
-
0
hi
- Download the
leptonxmodule source code and copy theaspnet-core/volo/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.LeptonX/Themes/LeptonX/Layouts/Account/Default.cshtmlto your project and hide the tenant selection component. - Download
accountpro module source code and copy theabp/account/src/Volo.Abp.Account.Pro.Public.Web/Pages/Account/Login.cshtmlto your project and add a new tenant name input. - Override the
public virtual async Task<IActionResult> OnPostAsync(string action)(abp/account/src/Volo.Abp.Account.Pro.Public.Web/Pages/Account/Login.cshtml.cs) to change the current tenant.
Thanks.
- Download the
-
0
Override the public virtual async Task<IActionResult> OnPostAsync(string action)(abp/account/src/Volo.Abp.Account.Pro.Public.Web/Pages/Account/Login.cshtml.cs) to change the current tenant.
Iām not clear about this step. Should I override it in the AuthServer? And in which file is the public virtual async Task<IActionResult> OnPostAsync(string action) method located?
-
0
hi
Yes, the authserver project
````csharp [ExposeServices(typeof (OpenIddictSupportedLoginModel), typeof(LoginModel))] public class MyLoginModel : OpenIddictSupportedLoginModel { public override Task<IActionResult> OnPostAsync(string action) { var your_tenant_name = "my_tenant";// get it from post request. using(Current.Change(your_tenant_name)) { return base.OnPostAsync(action); } } } -
0
Where should I add the code you provided? Please guide me step by step in detail. Thank you.
-
0
hi
You can add these class/cshtml files to your AuthServer project.
See https://abp.io/docs/latest/framework/ui/mvc-razor-pages/customization-user-interface#overriding-a-razor-page-cshtml https://abp.io/docs/latest/framework/ui/mvc-razor-pages/customization-user-interface#example-1