Open Closed

Tenant self registration admin role and email confirmation issue #7077


User avatar
0
franciscokadzi@gmail.com created
  • ABP Framework version: v7.4.2
  • UI Type: Angular
  • Database System: EF Core (SQL Server)
  • Tiered (for MVC) or Auth Server Separated (for Angular): yes
  • Exception message and full stack trace:
  • Steps to reproduce the issue:

I have the following questions

  1. I have tenant self registration configured, but one thing we realised is that the admin role can be removed for the admin user created during the tenant self registration. Why is that possible? Is there a way to fix that? Each tenant should have at least one admin user.
  2. I need all users to verify their emails before they are able to login, but that does not work for tenant registration. New tenants do not get the email confirmation email. I came across this ticket https://support.abp.io/QA/Questions/5042/Send-email-to-tenant-admin-on-tenant-creation. Is that feature now available? If yes how do I get it to work? If not, is there a workaround for it?

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

    hi

    1. the admin role can be removed for the admin user created during the tenant self registration.

    Can you explain it in detail? And share some screenshots?

    Thanks.

    2. You can add an IDistributedEventHandler<TenantCreatedEto> on the template project to send the mail.

  • User Avatar
    0
    franciscokadzi@gmail.com created

    hi

    1. the admin role can be removed for the admin user created during the tenant self registration.

    Can you explain it in detail? And share some screenshots?

    In the image, the role of admin can be removed by the user. Is it not the case that there must always be at least one admin for a tenant?

    For the emailing confirmation issue, I tried doing this but got user does not exist error. Can you help with a detailed code on getting this to work please?

    public async Task HandleEventAsync(TenantCreatedEto eventData)
    {
        var user = await UserManager.FindByEmailAsync(Input.EmailAddress);
        var code = await UserManager.GenerateEmailConfirmationTokenAsync(user);
    
        var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code }, protocol: HttpContext.Request.Scheme);
        await _emailSender.SendAsync(Input.EmailAddress, "Email confirmation",
            $"Please confirm your email address by clicking the following link.<br> <a href='{callbackUrl}'>Confirm my email address</a>.");
    
    }
    
  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    In the image, the role of admin can be removed by the user. Is it not the case that there must always be at least one admin for a tenant?

    We don't limit this operation. You can customize it.

    For the emailing confirmation issue, I tried doing this but got user does not exist error.

    Please try to change the current tenant id.

    public async Task HandleEventAsync(TenantCreatedEto eventData)
    {
        using (CurrentTenant.Change(eventData.Id))
        {
            var user = await UserManager.FindByEmailAsync(Input.EmailAddress);
            var code = await UserManager.GenerateEmailConfirmationTokenAsync(user);
        
            var callbackUrl = Url.Action("ConfirmEmail", "Account", new { userId = user.Id, code }, protocol: HttpContext.Request.Scheme);
            await _emailSender.SendAsync(Input.EmailAddress, "Email confirmation",
                $"Please confirm your email address by clicking the following link.
         Confirm my email address.");
        }
    }
    
  • User Avatar
    0
    franciscokadzi@gmail.com created

    Hi thanks for the help. The user not found issue is resolved now. But I get new errors. I have tried several options including AccountAppService.SendEmailConfirmationTokenAsync but to no avail. The HandleEventAsync is currently in my TenantRegister.cshtml.cs file.

    Can you provide me with specifics on how to get this done. Possibly provide me with the complete code and where exactly to place it, in order for it to work.

    I tried this option also

    public async Task HandleEventAsync(TenantCreatedEto eventData)
    {
        using (CurrentTenant.Change(eventData.Id))
        {
            var tenantEmail = eventData.Properties.GetOrDefault("AdminEmail");
            var user = await UserManager.FindByEmailAsync(tenantEmail);
    
    
            var emailArgs = new SendEmailConfirmationTokenDto
            {
                AppName = "MVC",
                ReturnUrl = ReturnUrl,
                ReturnUrlHash = ReturnUrlHash,
                UserId = user.Id,
            };
    
            await AccountAppService.SendEmailConfirmationTokenAsync(emailArgs);
    
        }
    }
    

    but I get NullReferenceException: Object reference not set to an instance of an object.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    Can you set a breakpoint to see which object is null?

    And don't use AccountAppService instead of injecting the UserManager and AccountEmailer to do same logic in your EventHandler,

    protected virtual async Task SendEmailConfirmationTokenAsync(
        IdentityUser user,
        string applicationName,
        string returnUrl,
        string returnUrlHash)
    {
        var confirmationToken = await UserManager.GenerateEmailConfirmationTokenAsync(user);
        await AccountEmailer.SendEmailConfirmationLinkAsync(user, confirmationToken, applicationName, returnUrl, returnUrlHash);
    }
    
  • User Avatar
    0
    franciscokadzi@gmail.com created

    hi

    Can you set a breakpoint to see which object is null?

    **returnUrl ** and **returnUrlHash ** are coming in as null

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    You can leave returnurl and returnurlhash as the empty string.

    And don't use AccountAppService instead of injecting the UserManager and AccountEmailer to do same logic in your EventHandler,

  • User Avatar
    0
    franciscokadzi@gmail.com created
    public async Task HandleEventAsync(TenantCreatedEto eventData) 
    { 
        using (CurrentTenant.Change(eventData.Id)) 
        { 
            var tenantEmail = eventData.Properties.GetOrDefault("AdminEmail"); 
            var user = await UserManager.FindByEmailAsync(tenantEmail); 
     
     
            var emailArgs = new SendEmailConfirmationTokenDto 
            { 
                AppName = "MVC", 
                ReturnUrl = ReturnUrl, 
                ReturnUrlHash = ReturnUrlHash, 
                UserId = user.Id, 
            }; 
     
            await AccountAppService.SendEmailConfirmationTokenAsync(emailArgs); 
     
        } 
    } 
    

    This code works after upgrading to ABP 8. But I am faced with a new problem. after successfully confirming the email the "Login to application" button on the email confirmation page does not contain the correct return URL for the tenant. this is what I get

    https://yahoo.localhost:44348/Account/Login?returnUrl=~%2F

    I tried to manually set the redirect url but that did not work either

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    What's the value of ReturnUrl?

    And does your URL exist in RedirectAllowedUrls?

    {
      "App": {
        "RedirectAllowedUrls": "http://localhost:4200,https://localhost:44307"
      }
    }
    
  • User Avatar
    0
    listtraderdev2 created

    hi

    What's the value of ReturnUrl?

    the returnUrl is returnUrl=~%2F please check the image attached earlier.

    And does your URL exist in RedirectAllowedUrls?

    { 
      "App": { 
        "RedirectAllowedUrls": "http://localhost:4200,https://localhost:44307" 
      } 
    } 
     
    

    Yes my URL exists in RedirectAllowedUrls

    {
      "App": {
      "RedirectAllowedUrls": "http://{{tenantName}}.localhost:4200,https://{{tenantName}}.localhost:44348"
      }
    

    I also tried using it without the {{tenantName}}

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    What's the ReturnUrl value of emailArgs?

    var emailArgs = new SendEmailConfirmationTokenDto 
    { 
        AppName = "MVC", 
        ReturnUrl = ReturnUrl, 
        ReturnUrlHash = ReturnUrlHash, 
        UserId = user.Id, 
    }; 
    
  • User Avatar
    0
    franciscokadzi@gmail.com created

    The value is null

    even when I set it manually the button does not get the correct value.

    This is the confirmation page link I get. You can see that the returnUrl value is added

    https://st.localhost:44348/Account/EmailConfirmation?userId=97487596-3730-b62d-689f-3a1296a2b934&__tenant=00b2e43b-46db-745c-7db4-3a1296a2b6f4&confirmationToken=CfDJ8B5ozhcWAFlNj4ZmTrh5rF4R8AdTcFhmp%2F14OKgLb8uaxmPpDeJuLFpWT3O%2FhiupLSXepzJk2rM5EtDC%2F%2FNPKw5R56vahTyBuwSQCRAs7zEqnymCAb7DFIhrfhaScmdQED01%2B2ul5hrAMFcJnph%2FITgviLMvfS1qIuOtxOG8GeEFPe%2BIhBgIramiIalxk1pERNfqO5sTntRq5%2FeY3DeN77sZbfS4p6ic8McZQabSewA4br6Drlf2GudEQHyLrmXc1w%3D%3D&returnUrl=https://st.localhost

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi franciscokadzi

    Can you share a simple project?

    liming.ma@volosoft.com

    Thanks

  • User Avatar
    0
    franciscokadzi@gmail.com created

    Hi Maliming Can we rather get on a call. Zoom, Google meet or Teams

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    hi

    The returnurl(https://st.localhost) must be exists on RedirectAllowedUrls

    And you can override the EmailConfirmationModel modal to debug it

    Volo.Abp.Account.Pro.Public.Web/Pages/Account/EmailConfirmation.cshtml Volo.Abp.Account.Pro.Public.Web/Pages/Account/EmailConfirmation.cshtml.cs

  • User Avatar
    0
    franciscokadzi@gmail.com created

    The tenant names are not pre-determined. Users are expected to register as tenants with tenant names of their choosing. For this reason I wont be able to add the names to the RedirectAllowedUrls before they are created. We have configured wildcards to take care of this.

    I will try override the EmailConfirmationModel as you suggested

  • User Avatar
    1
    maliming created
    Support Team Fullstack Developer

    ok, Please check the GetRedirectUrlAsync method.

    https://github.com/abpframework/abp/blob/dev/framework/src/Volo.Abp.AspNetCore.Mvc.UI/Volo/Abp/AspNetCore/Mvc/UI/RazorPages/AbpPageModel.cs#L130-L160

  • User Avatar
    0
    franciscokadzi@gmail.com created

    Thank you. I have resolved it by overriding the EmailConfirmationModel I have replaced this ./Login from <a abp-button="Primary" href="@Url.Page("./Login", new {returnUrl = Model.ReturnUrl, returnUrlHash = Model.ReturnUrlHash})">@L["LoginToTheApplication"]</a> by dynamically setting the full URL of the tenant.

  • User Avatar
    0
    maliming created
    Support Team Fullstack Developer

    👍

Made with ❤️ on ABP v9.1.0-preview. Updated on December 10, 2024, 06:38