- ABP Framework version: v9.X.X
- UI Type: MVC / Blazor WASM / Blazor Server
- Database System: EF Core (SQL Server, Oracle, MySQL, PostgreSQL, etc..) / MongoDB
- Tiered (for MVC) or Auth Server Separated (for Angular): no
- Exception message and full stack trace:
- Steps to reproduce the issue:
We are trying to add a textbox on the register page, users can put a code in and we will use the code to pick a tenant for them, so instead of using https://localhost:44381/Account/register?__tenant=lego they will just use https://localhost:44381/Account/register and put a code 'lego' on the new textbox and then the code behind will select lego as the tenant how can we do that? thanks
7 Answer(s)
-
0
-
0
Here are what we wanted
- removing the current tenant switch;
- adding a new textbox called Invite Code
- creating a function to map the invite codes to tenant id (for example, XDEF(Code) -> test(Tenant Id); i.e. when type XDEF for code, users will create a new account for test tenant
The reason we do this is that we don't want to expose the platform's tenants externally.
-
0
I understand, for this you need to override the login page first. Then you can make the changes you want. You can follow the steps below to override the login page.
- Create Account folder in Pages folder like below:
- Create Login.cshtml and Login.cshml.cs files in Account folder.
- Update Login.cshtml and Login.cshml.cs files like below:
Login.cshtml
@page @using Microsoft.AspNetCore.Mvc.Localization @using Microsoft.AspNetCore.Mvc.TagHelpers @using Microsoft.Extensions.Options @using Owl.reCAPTCHA @using Owl.reCAPTCHA.v2.TagHelpers @using Owl.reCAPTCHA.v3.TagHelpers @using Volo.Abp.Account.Localization @using Volo.Abp.Account.Public.Web.Pages.Account; @using Volo.Abp.Account.Public.Web.Security.Recaptcha @using Volo.Abp.Account.Settings @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Alert @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button @using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Grid @using Volo.Abp.AspNetCore.Mvc.UI.Bundling.TagHelpers @using Volo.Abp.Settings @model NonTieredApp.Web.Pages.Account.TappLoginModel @inject IHtmlLocalizer<AccountResource> L @inject Volo.Abp.AspNetCore.Mvc.UI.Layout.IPageLayout PageLayout @inject ISettingProvider SettingProvider @{ PageLayout.Content.Title = L["Login"].Value; var reCaptchaVersion = await SettingProvider.GetAsync<int>(AccountSettingNames.Captcha.Version); if (Model.UseCaptcha) { await Model.ReCaptchaOptions.SetAsync(reCaptchaVersion == 3 ? reCAPTCHAConsts.V3 : reCAPTCHAConsts.V2); } } @section scripts { <abp-script-bundle name="@typeof(LoginModel).FullName"> <abp-script src="/Pages/Account/Login.js" /> </abp-script-bundle> @if (Model.UseCaptcha) { if (reCaptchaVersion == 3) { <recaptcha-script-v3 /> <recaptcha-script-v3-js action="login" execute="false" /> } else { <recaptcha-script-v2 /> } } } @if (Model.IsLinkLogin) { <abp-alert alert-type="Warning"> @L["LinkAccountWarning", Url.PageLink()] </abp-alert> } @if (Model.BackToExternalLogins) { <div class="d-grid gap-2"> <a class="mb-3 btn btn-primary btn-block" href="@Url.Page("./ExternalLogins")">@L["Back"]</a> </div> } <div class="account-module-form"> @if (Model.IsSelfRegistrationEnabled) { <h5 class="mb-2">@L["NotAMemberYet"] <a class="text-decoration-none" href="@Url.Page("./Register", new {returnUrl = Model.ReturnUrl, returnUrlHash = Model.ReturnUrlHash})">@L["Register"]</a></h5> } @if (Model.EnableLocalLogin) { <form method="post" id="loginForm"> @if (Model.UseCaptcha) { <input class="mb-3" data-captcha="true" type="hidden" name="@RecaptchaValidatorBase.RecaptchaResponseKey" id="@RecaptchaValidatorBase.RecaptchaResponseKey"/> } <div> <div class="form-floating mb-2"> <input asp-for="LoginInput.UserNameOrEmailAddress" type="text" class="form-control" placeholder="name@example.com"> @Html.LabelFor(m => m.LoginInput.UserNameOrEmailAddress, "Email Address") <span asp-validation-for="LoginInput.UserNameOrEmailAddress"/> </div> <div class="form-floating mb-2"> <input asp-for="LoginInput.Password" id="password-input" type="password" class="form-control" placeholder="Password"> @Html.LabelFor(m => m.LoginInput.Password) <i id="PasswordVisibilityButton" class="bi bi-eye-slash show-pass-icon" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-html="true" aria-label="@L["ShowPassword"]" data-bs-original-title="@L["ShowPassword"]"></i> <i id="capslockicon" class="bi bi-capslock caps-lock-icon" style="display: none;" data-bs-toggle="tooltip" data-bs-placement="top" data-bs-html="true" aria-label="<i class='bi bi-exclamation-circle'></i> @L["CapsLockOn"]!" data-bs-original-title="<i class='bi bi-exclamation-circle'></i> @L["CapsLockOn"]!"></i> <span asp-validation-for="LoginInput.Password"/> </div> </div> <abp-row> <abp-column> <div class="form-switch ps-2"> <abp-input asp-for="LoginInput.RememberMe" class="mb-4"/> </div> </abp-column> <abp-column class="text-end"> <a href="@Url.Page("./ForgotPassword", new {returnUrl = Model.ReturnUrl, returnUrlHash = Model.ReturnUrlHash})">@L["ForgotPassword"]</a> </abp-column> </abp-row> @if (reCaptchaVersion == 2) { <script> recaptchaCallback = function (token) { $('form button[type=submit]').removeAttr("disabled"); $('#@RecaptchaValidatorBase.RecaptchaResponseKey').val(token) }; </script> <div class="mb-3"> <recaptcha-div-v2 callback="recaptchaCallback"/> </div> } <div class="d-grid gap-2"> <abp-button button-type="Primary" type="submit" class="mb-3" name="Action" value="Login" disabled="true"> <i class="bi bi-box-arrow-in-right me-1"></i> @L["Login"] </abp-button> </div> @if (Model.ShowCancelButton) { <div class="d-grid gap-2"> <abp-button button-type="Secondary" type="submit" formnovalidate="formnovalidate" class="mb-3" name="Action" value="Cancel">@L["Cancel"]</abp-button> </div> } </form> } @if (Model.VisibleExternalProviders.Any() && false) { if(Model.EnableLocalLogin) { <hr/> @L["OrSignInWith"] <br/> } else { @L["SignInWithOneOfTheFollowingProviders"] } <form asp-page="./Login" asp-page-handler="ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" asp-route-returnUrlHash="@Model.ReturnUrlHash" asp-route-linkTenantId="@Model.LinkTenantId" asp-route-linkUserId="@Model.LinkUserId" asp-route-linkToken="@Model.LinkToken" method="post"> @foreach (var provider in Model.VisibleExternalProviders) { <button type="submit" class="mt-2 me-2 btn btn-outline-primary btn-sm" name="provider" value="@provider.AuthenticationScheme" data-busy-text="@L["ProcessingWithThreeDot"]"> @if (provider.Icon != null) { <i class="@provider.Icon"></i> } <span>@provider.DisplayName</span> </button> } </form> } </div>
Login.cshtml.cs
using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Identity; using Microsoft.Extensions.Options; using Owl.reCAPTCHA; using Volo.Abp.Account.ExternalProviders; using Volo.Abp.Account.Public.Web; using Volo.Abp.Account.Public.Web.Pages.Account; using Volo.Abp.Account.Security.Recaptcha; using Volo.Abp.Auditing; using Volo.Abp.Security.Claims; namespace NonTieredApp.Web.Pages.Account; [DisableAuditing] public class TappLoginModel : LoginModel { public TappLoginModel( IAuthenticationSchemeProvider schemeProvider, IOptions<AbpAccountOptions> accountOptions, IAbpRecaptchaValidatorFactory recaptchaValidatorFactory, IAccountExternalProviderAppService accountExternalProviderAppService, ICurrentPrincipalAccessor currentPrincipalAccessor, IOptions<IdentityOptions> identityOptions, IOptionsSnapshot<reCAPTCHAOptions> reCaptchaOptions) : base( schemeProvider, accountOptions, recaptchaValidatorFactory, accountExternalProviderAppService, currentPrincipalAccessor, identityOptions, reCaptchaOptions) { } }
You can then customize it any way you want. If you have a specific question in the implementation, you can ask.
-
0
I can see we have the code in layout default.cshtml <div> <div class="row"> <div class="col"> <span style="font-size: .8em;" class="text-uppercase text-muted">@MultiTenancyStringLocalizer["Tenant"]</span><br /> <h6 class="m-0 d-inline-block"> @if (CurrentTenant.Id == null) { <span> @MultiTenancyStringLocalizer["NotSelected"] </span> } else { <strong> @(CurrentTenant.Name ?? CurrentTenant.Id.Value.ToString()) </strong> } </h6> </div> <div class="col-auto"> <a id="AbpTenantSwitchLink" href="javascript:;" class="btn btn-sm btn-outline-primary">@MultiTenancyStringLocalizer["Switch"]</a> </div> </div> </div>
- I can't find the js code to set the tenant with the __tenant value in querystring, can you show me where the js function is? because I want to change the UI a little bit. or is it just set by QueryStringTenantResolveContributor? QueryStringTenantResolveContributor -> CurrentTenant-> CurrentTenant.Name
- can you show me where the code for the switch tenant pop up window is? I couldn't find it
-
0
I can't find the js code to set the tenant with the __tenant value in querystring, can you show me where the js function is? because I want to change the UI a little bit. or is it just set by QueryStringTenantResolveContributor? QueryStringTenantResolveContributor -> CurrentTenant-> CurrentTenant.Name
When you remove tenant selection from the UI, the parameter from the query will not be very important. So you don't need to worry about it.
can you show me where the code for the switch tenant pop up window is? I couldn't find it
This code comes from the layout of the theme.
You can also look at the content published on this topic. See:
- https://abp.io/community/articles/hide-the-tenant-switch-of-the-login-page-4foaup7p
- https://abp.io/support/questions/1399/How-to-hide-Tenant-switch-from-login-page-but-without-disable-tenant
- https://abp.io/support/questions/4914/ABP-Login-Hiding-Tenant--checking-the-user-in-which-tenant-to-sign-in-Directly
-
0
*can you show me where the code for the switch tenant pop up window is? I couldn't find it
This code comes from the layout of the theme. * I meant the modal, I found it for the mauiblazor , but couldn't find it for the MVC project: <Modal @ref="SwitchTenantModal" Closing="@SwitchTenantModal.CancelClosingModalWhenFocusLost"> <ModalContent Centered="true"> <Form> <ModalHeader> <ModalTitle>@L["SwitchTenant"]</ModalTitle> <CloseButton Clicked="CloseSwitchTenantModalAsync"/> </ModalHeader> <ModalBody> <Field> <FieldLabel>@L["Name"] *</FieldLabel> <TextEdit @bind-Text="TenantName" Autofocus="true"/> <div class="form-text">@L["SwitchTenantHint"]</div> </Field> </ModalBody> <ModalFooter> <Button Color="Color.Secondary" Clicked="CloseSwitchTenantModalAsync">@L["Cancel"]</Button> <SubmitButton Clicked="@SwitchTenantAsync"/> </ModalFooter> </Form> </ModalContent> </Modal>
-
0
Hi,
I got it, this code comes from the Multi-Tenancy(open-source) module. Here is the code: https://github.com/abpframework/abp/blob/6f8847dd012fa715be029385b9bc1b52e1a0afd5/framework/src/Volo.Abp.AspNetCore.Mvc.UI.MultiTenancy/Pages/Abp/MultiTenancy/TenantSwitchModal.cshtml