Open Closed

Pre-fill Username on Login with Login Hint #9279


User avatar
0
MichelZ created
  • Template: app
  • Created ABP Studio Version: 0.9.12
  • Current ABP Studio Version: 0.9.26
  • Tiered: Yes
  • Multi-Tenancy: Yes
  • UI Framework: angular
  • Theme: leptonx
  • Theme Style: system
  • Progressive Web App: No
  • Database Provider: ef
  • Database Management System: postgresql
  • Separate Tenant Schema: Yes
  • Mobile Framework: none
  • Public Website: Yes
  • Include Tests: Yes
  • Optional Modules:
    • GDPR
    • FileManagement
    • TextTemplateManagement
    • LanguageManagement
    • AuditLogging
    • SaaS
    • OpenIddictAdmin

We are trying to add a login hint to the login page on the Auth Server (MVC), and thought that's an easy task, but for some reason can't get it to work :( We are overriding the Login.cs page by having a OurProductLogin.cshtml.cs file in /Pages/Account (as well as the _ViewImports.cshtml)

Content of OurProductLogin.cshtml.cs:

using System.Threading.Tasks;
using company.Product.Saas;
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
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.DependencyInjection;
using Volo.Abp.Security.Claims;
using Volo.Abp.Uow;

namespace company.Product.Pages.Account;

[DisableAuditing]
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(LoginModel))]
public class OurProductLoginModel: LoginModel
{
    [BindProperty(SupportsGet = true)]
    public string? test { get; set; }

    public OurProductLoginModel(
        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)
    {
    }

    public override async Task<IActionResult> OnGetAsync()
    {
        var result = await base.OnGetAsync();

        if (!string.IsNullOrEmpty(test))
        {
            LoginInput.UserNameOrEmailAddress = test;
        }

        return result;
    }
}

As you can see, this seems as simple as it can get :) However, when using a Browser GET request to /Account/Login?test=test@test.com, the Username field is not pre-filled as we'd expect. What are we doing wrong?

(Note: We have also tried this permutation of the OnGetAsync() function, without relying on the base.OnGetAsync()):

public override async Task<IActionResult> OnGetAsync()
{
    LoginInput = new LoginInputModel();
    if (!string.IsNullOrEmpty(test))
    {
        LoginInput.UserNameOrEmailAddress = test;
    }

    var localLoginResult = await CheckLocalLoginAsync();
    if (localLoginResult != null)
    {
        return localLoginResult;
    }
    
    IsSelfRegistrationEnabled = await SettingProvider.IsTrueAsync(AccountSettingNames.IsSelfRegistrationEnabled);

    UseCaptcha = await UseCaptchaOnLoginAsync();

    IsLinkLogin = await VerifyLinkTokenAsync();
    if (IsLinkLogin)
    {
        if (CurrentUser.IsAuthenticated)
        {
            await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext
            {
                Identity = IdentitySecurityLogIdentityConsts.Identity,
                Action = IdentitySecurityLogActionConsts.Logout
            });

            await SignInManager.SignOutAsync();

            return Redirect(HttpContext.Request.GetDisplayUrl());
        }
    }

    return Page();
}

Also note: While debugging, the Property test is indeed null in the OnGetAsync() method.

Edit: The more I try to understand this, the more questions I have :) What's the deal with OpenIddictSupportedLoginModel, do I need to use this? (I can't really find any official documentation about this, so I assume not? If yes -> Documentation definitely needs to be improved). In there, it seems that it <could> use a LoginHint already, but the base.OnGetAsync() overwrites the LoginInput property and would erase the value again, right?

Thanks Michel


10 Answer(s)
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    If you are using OpenIddict, you need to override the OpenIddictSupportedLoginModel

    
    [ExposeServices(typeof(LoginModel), typeof(OpenIddictSupportedLoginModel))]
    public class MyOpenIddictSupportedLoginModel : OpenIddictSupportedLoginModel
    

    I have update the document.

    https://github.com/abpframework/abp/pull/22770

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    If overriding OpenIddictSupportedLoginModel still does not work. Can you share a test project?

    liming.ma@volosoft.com

    Thanks

  • User Avatar
    0
    MichelZ created

    I've shared a test project via E-Mail

  • User Avatar
    0
    MichelZ created

    I have also created a PR to fix the overwriting of the Login Hint: https://github.com/abpframework/abp/pull/22887

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    [DisableAuditing]
    [Dependency(ReplaceServices = true)]
    [ExposeServices(typeof(LoginModel), typeof(OpenIddictSupportedLoginModel))]
    public class MyCustomLogin : OpenIddictSupportedLoginModel
    {
        public MyCustomLogin(IAuthenticationSchemeProvider schemeProvider, IOptions<AbpAccountOptions> accountOptions, IAbpRecaptchaValidatorFactory recaptchaValidatorFactory, IAccountExternalProviderAppService accountExternalProviderAppService, ICurrentPrincipalAccessor currentPrincipalAccessor, IOptions<IdentityOptions> identityOptions, IOptionsSnapshot<reCAPTCHAOptions> reCaptchaOptions, AbpOpenIddictRequestHelper openIddictRequestHelper) : base(schemeProvider, accountOptions, recaptchaValidatorFactory, accountExternalProviderAppService, currentPrincipalAccessor, identityOptions, reCaptchaOptions, openIddictRequestHelper)
        {
        }
    
        public override async Task<IActionResult> OnGetAsync()
        {
            var result = await base.OnGetAsync();
    
            if (LoginInput.UserNameOrEmailAddress.IsNullOrWhiteSpace())
            {
                LoginInput.UserNameOrEmailAddress = Request.Query["TestUrlParameter"];
            }
    
            return result;
        }
    }
    

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    I have also created a PR to fix the overwriting of the Login Hint: https://github.com/abpframework/abp/pull/22887

    Thanks. I will check it. : )

  • User Avatar
    0
    MichelZ created

    hi

    [DisableAuditing] 
    [Dependency(ReplaceServices = true)] 
    [ExposeServices(typeof(LoginModel), typeof(OpenIddictSupportedLoginModel))] 
    public class MyCustomLogin : OpenIddictSupportedLoginModel 
    { 
        public MyCustomLogin(IAuthenticationSchemeProvider schemeProvider, IOptions<AbpAccountOptions> accountOptions, IAbpRecaptchaValidatorFactory recaptchaValidatorFactory, IAccountExternalProviderAppService accountExternalProviderAppService, ICurrentPrincipalAccessor currentPrincipalAccessor, IOptions<IdentityOptions> identityOptions, IOptionsSnapshot<reCAPTCHAOptions> reCaptchaOptions, AbpOpenIddictRequestHelper openIddictRequestHelper) : base(schemeProvider, accountOptions, recaptchaValidatorFactory, accountExternalProviderAppService, currentPrincipalAccessor, identityOptions, reCaptchaOptions, openIddictRequestHelper) 
        { 
        } 
     
        public override async Task<IActionResult> OnGetAsync() 
        { 
            var result = await base.OnGetAsync(); 
     
            if (LoginInput.UserNameOrEmailAddress.IsNullOrWhiteSpace()) 
            { 
                LoginInput.UserNameOrEmailAddress = Request.Query["TestUrlParameter"]; 
            } 
     
            return result; 
        } 
    } 
    

    Yes, that is a workaround. But the default databinding of ASP.NET Core should also work, shouldn't it?

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    I think the ASP.NET Core only checks the BindProperty of the base LoginModel class.

  • User Avatar
    0
    MichelZ created

    hi

    I think the ASP.NET Core only checks the BindProperty of the base LoginModel class.

    Somehow I was under the impression that this should work, but if it's the expected behavior, then that's fine of course.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    : )

Boost Your Development
ABP Live Training
Packages
See Trainings
Mastering ABP Framework Book
Do you need assistance from an ABP expert?
Schedule a Meeting
Mastering ABP Framework Book
The Official Guide
Mastering
ABP Framework
Learn More
Mastering ABP Framework Book
Made with ❤️ on ABP v9.3.0-preview. Updated on May 12, 2025, 05:22