How can I override the UI of the login page using Identity server/Blazor. There is an article in the community section however it appears to be based on a earlier version of ABP where the 'LoginModel' class is in a different namespace.
ABP Framework version:** v4.4 UI type**: Blazor DB provider**: EF Core Identity Server Separated: yes
14 Answer(s)
-
0
Hi,
I'm assuming you have created the Account folder in the Pages folder of the
MyProjectName.IdentityServer
project :)CustomLoginModel.cs in Account folder
[Dependency(ReplaceServices = true)] [ExposeServices(typeof(LoginModel))] public class CustomLoginModel : LoginModel { public CustomLoginModel( 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) { Console.WriteLine("Test QA Question"); } }
Please let us know if it works after you try it.
-
0
-
0
Hi,
I'm assuming you have created the Account folder in the Pages folder of the
MyProjectName.IdentityServer
project :)CustomLoginModel.cshtml in Account folder
[Dependency(ReplaceServices = true)] [ExposeServices(typeof(LoginModel))] public class CustomLoginModel : LoginModel { public CustomLoginModel( 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) { Console.WriteLine("Test QA Question"); } }
Please let us know if it works after you try it.
I'm a little confused by your response as you mentioned that this should be done in the cshtml file not the class. Could you list exactly what I need to do in order to do this as I've seend some conflicting information in the documentation.
Thanks
-
0
Hi,
I'm assuming you have created the Account folder in the Pages folder of the
MyProjectName.IdentityServer
project :)CustomLoginModel.cshtml in Account folder
[Dependency(ReplaceServices = true)] [ExposeServices(typeof(LoginModel))] public class CustomLoginModel : LoginModel { public CustomLoginModel( 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) { Console.WriteLine("Test QA Question"); } }
Please let us know if it works after you try it.
I'm a little confused by your response as you mentioned that this should be done in the cshtml file not the class. Could you list exactly what I need to do in order to do this as I've seend some conflicting information in the documentation.
Thanks
To be more specific I want to override the look of of the login page, meaning I don't want the tennant selector and I also want to add/remove items in the login box and do custom code (calling different services) behind the various button clicks.
-
0
First of all it will be CustomLoginModel.cs not CustomLoginModel.cshtml :(
So it's my fault that you're confused, I hope I can make up for it :)
If we have to go step by step 👇
- Create a new Login.cshtml under
Pages\Account
folder
Login.cshtml
@page @using Microsoft.AspNetCore.Mvc.Localization @using Microsoft.Extensions.Options @using Owl.reCAPTCHA @using Volo.Abp.Account.Localization @using Volo.Abp.Account.Public.Web.Security.Recaptcha @using Volo.Abp.Account.Settings @using Volo.Abp.Settings @model Volo.Abp.Account.Public.Web.Pages.Account.LoginModel @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 src="/Pages/Account/Login.js" /> @if (Model.UseCaptcha) { if (reCaptchaVersion == 3) { <recaptcha-script-v3/> <recaptcha-script-v3-js action="login" callback="(function(){$('#@RecaptchaValidatorBase.RecaptchaResponseKey').val(token)})"/> } else { <recaptcha-script-v2/> } } } @section styles { <abp-style src="/Pages/Account/Login.css" /> } @if (Model.IsLinkLogin) { <abp-alert alert-type="Warning"> @L["LinkAccountWarning", Url.PageLink()] </abp-alert> } <div class="account-module-form"> @if (Model.EnableLocalLogin) { <form method="post"> @if (Model.UseCaptcha) { <input type="hidden" name="@RecaptchaValidatorBase.RecaptchaResponseKey" id="@RecaptchaValidatorBase.RecaptchaResponseKey"/> } <p>Test QA Question: 1668</p> <abp-input asp-for="LoginInput.UserNameOrEmailAddress" required-symbol="false"/> <abp-input asp-for="LoginInput.Password" required-symbol="false"/> <abp-row> <abp-column> <abp-input asp-for="LoginInput.RememberMe" class="mb-4"/> </abp-column> <abp-column class="text-right"> <a href="@Url.Page("./ForgotPassword", new { returnUrl = Model.ReturnUrl, returnUrlHash = Model.ReturnUrlHash })">@L["ForgotPassword"]</a> </abp-column> </abp-row> @if (reCaptchaVersion == 2) { <recaptcha-div-v2 callback="(function(){$('#@RecaptchaValidatorBase.RecaptchaResponseKey').val(token)})" /> } <abp-button button-type="Primary" size="Block" type="submit" class="mt-2 mb-3" name="Action" value="Login">@L["Login"]</abp-button> @if (Model.ShowCancelButton) { <abp-button button-type="Secondary" size="Block" type="submit" formnovalidate="formnovalidate" class="mt-2 mb-3" name="Action" value="Cancel">@L["Cancel"]</abp-button> } </form> if (Model.IsSelfRegistrationEnabled) { @L["NotAMemberYet"] <a href="@Url.Page("./Register", new {returnUrl = Model.ReturnUrl, returnUrlHash = Model.ReturnUrlHash})">@L["Register"]</a> } } @if (Model.VisibleExternalProviders.Any()) { <hr/> @L["OrSignInWith"]<br/> <form asp-page="./Login" asp-page-handler="ExternalLogin" asp-route-returnUrl="@Model.ReturnUrl" asp-route-returnUrlHash="@Model.ReturnUrlHash" method="post"> @foreach (var provider in Model.VisibleExternalProviders) { <button type="submit" class="mt-2 mr-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> } @if (!Model.EnableLocalLogin && !Model.VisibleExternalProviders.Any()) { <div class="alert alert-warning"> <strong>Invalid login request</strong> There are no login schemes configured for this client. </div> } </div>
Then... 👇👇👇
- Create a new Login.cshtml under
-
0
- Create CustomLoginModel.cs file in the same folder (
Pages\Account
) CustomLoginModel.cs
using System; 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.DependencyInjection; using Volo.Abp.Security.Claims; namespace TestQABZ.Pages.Account { [Dependency(ReplaceServices = true)] [ExposeServices(typeof(LoginModel))] public class CustomLoginModel : LoginModel { public CustomLoginModel( 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) { Console.WriteLine("Test QA"); } } }
- Add a CSS to play with the existing styles. Create Login.css in the same folder (
Pages\Account
) Login.css
.container { background-color: #d0d08c; } .card { background: #bccce4; }
- Add a JS to write JavaScript. Create Login.js in the same folder (
Pages\Account
) Login.js
alert('login page loaded.');
When we do all these, you will have a structure similar to the one below:
Once it's up and running, you can make any changes you want, but if you encounter a problem, please let us know again.
- Create CustomLoginModel.cs file in the same folder (
-
0
-
0
Keep in mind I'm trying to override the login page at the 'public' web application level, not Identity Server.
-
0
Hi,
In our previous conversations, you did not say that you want to do it on the public web side.
As a solution: Compare the
MyProjectNameWebPublicModule
in theMyProjectName.Web.Public
project with theMyProjectNameIdentityServerModule
in theMyProjectName.IdentityServer
project and add the missing ones to theMyProjectNameWebPublicModule
. As a result, you will reach the view in the image below.Please let us know if it works after you try it.
-
0
Hi,
That resolved what I was trying to accomplish, but I'm still getting other errors. Do you have an working example of a public web site where I can completely override not only the UI aspect of the login page but also put additional logic in the OnPostAsync methed of the login page to do additional processing after the base Volo.Abp.Account.Public.Web.Pages.Account.LoginModel OnPostAsync method runs?
The Volo.EasyCrm real world application does not implement the login page in this same way.
Steve.
-
0
Hi,
To do this, you need to override the
OnPostAsync
method;// For example public override async Task<IActionResult> OnPostAsync(string action) { Console.WriteLine("OnPost - Before"); var result = await base.OnPostAsync(action); Console.WriteLine("OnPost - After"); return result; }
Then remove the following two lines from the
ConfigureAuthentication
method inMyProjectNamePublicWebModule
.options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc";
The final state should be as in the picture;
Finally, add the following code to the
appsettings.json
file of theMyProjectName.Web.Public
project:"ConnectionStrings": { "Default": "MY-CONNECTION-STRING" }
You can try to run the application and login to the public web side.
Note: If you encounter a problem like the picture below after logging in, remove the relevant places from
MyProjectNamePublicMenuContributor
.As a result, you can now login via the Public web application and customize it as you wish.
-
0
Ok, I was finally able to get this to work. My question now is how can I interrogate whether or not the user was successfully authenticated after the .base.OnPostAsync(action) result is returned. I don't see an obvious way to determine this.
// For example public override async Task<IActionResult> OnPostAsync(string action) { Console.WriteLine("OnPost - Before"); var result = await base.OnPostAsync(action); Console.WriteLine("OnPost - After");
return result; }
-
0
Disregard. It looks like I'm having an issue with identity server and the 'CurrentUser.IsAuthenticated' property is never being set to true.
-
0
Actually, I faced the same problem, and deleting the following two lines that I said in my previous answer solved my problem.
Then remove the following two lines from the ConfigureAuthentication method in MyProjectNamePublicWebModule.
options.DefaultScheme = "Cookies"; options.DefaultChallengeScheme = "oidc";
I think you can search other places where this is used and delete and test the ones you find one by one.
However, since this issue has been resolved, I'm closing this here.