Base solution for your next web application
Open Closed

Multi-Tenancy (Tenancy name) #8276


User avatar
0
christianharo created

Hello,

I have purchased ASPNEt Zero to create a new project. This project will make use of multi-tenancy and will be using a single database as I plan to host this in azure. The tenants will be able to create users in their own with different roles and permisions.

Question :

Aspet Zero (ABP) uses "Tenancy name" at login time to recognize the correct Tentant. This can be confusing/troublesome for the tentant and their users if this name is fogoten will casuse administration issues , if the tenats and their users are usign a new device

Is there an out of the box way that the Tenacy name is automatically recongnized based on the username and password ? if not Is there an example in how to correctly implement this using the framework ?

Thank you.


5 Answer(s)
  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @christianharo,

    Another approach would be using tenancy name as the subdomain like {TENANCY_NAME}.mywebsite.com. This is already implemented in the framework. If you configure your DNS records etc..., AspNet Zero will recognize the tenant.

    Here is the documentaion which explains how current tenant is determined, https://aspnetboilerplate.com/Pages/Documents/Multi-Tenancy#determining-current-tenant. You can inject your own login into there if you want.

    If you have a solution on your mind to determine the tenant from user information (for example email domain of user. For example, [email protected] will belong to tenant named MyCompany), I can suggest you someting more specific.

    Thanks,

  • User Avatar
    0
    christianharo created

    Hello,

    1.- I was hoping to resolve this without use of the DNS as this will be hosted in an azure site 2.- I am not tryiing to implement anything like [email protected] will belong to tenant named MyCompany. As many of the users will have like gmail addresses.

    I was trying to resolve the name og the tenant by only making use of the email and password.

  • User Avatar
    0
    ismcagdas created
    Support Team

    Hi @christianharo

    Then you can query AbpUserAccounts table on login process and get the recod only by using EmailAddress. This table, AbpUserAccounts, contains user records of all tenants & host.

    After that, you can switch to target Tenant context, https://aspnetboilerplate.com/Pages/Documents/Multi-Tenancy#switching-between-host-and-tenants, and continue to default login process.

  • User Avatar
    0
    ismcagdas created
    Support Team

    This issue is closed because of no recent activity. Please create a new issue if you are still having this problem.

  • User Avatar
    0
    eamonkeane created

    I would like to add my code here to help anyone that comes across this thread.

    I created a custom UserAccount repository with a new method which ignores the IMustHaveTenant filter.

    I then modified the Authenticate method within the TokenAuthController

      public async Task<AuthenticateResultModel> Authenticate([FromBody] AuthenticateModel model)
            {
                if (UseCaptchaOnLogin())
                {
                    await ValidateReCaptcha(model.CaptchaResponse);
                }
    
                var user = await _userAccountRepository.FindByUsernameOrEmailAddressIgnoreTenant(model.UserNameOrEmailAddress);
    
                var userTenantId = user.TenantId;
    
                   var tenancyNameOrNull =
                    userTenantId.HasValue ? _tenantCache.GetOrNull(userTenantId.Value)?.TenancyName : null;
    
                var loginResult = await GetLoginResultAsync(
                    model.UserNameOrEmailAddress,
                    model.Password,
                    tenancyNameOrNull
                );
                ..................
                ..........
    
    

    Custom UserAccountRepository

    public class UserAccountRepository: RinavoreRepositoryBase<UserAccount, long>, IUserAccountRepository
        {
            private readonly IDbContextProvider<RinavoreDbContext> _contextProvider;
            private readonly IUnitOfWorkManager _unitOfWorkManager;
    
            public UserAccountRepository(IDbContextProvider<RinavoreDbContext> contextProvider, IUnitOfWorkManager unitOfWorkManager):base(contextProvider)
            {
                _contextProvider = contextProvider;
                _unitOfWorkManager = unitOfWorkManager;
            }
    
            public Task<UserAccount> FindByUsernameOrEmailAddressIgnoreTenant(string usernameOrEmailAddress)
            {
                var context = _contextProvider.GetDbContext();
    
                using (_unitOfWorkManager.Current.DisableFilter(AbpDataFilters.MustHaveTenant))
                {
                    var user = context.UserAccounts.FirstOrDefaultAsync(ua => ua.EmailAddress == usernameOrEmailAddress || ua.UserName == usernameOrEmailAddress);
    
                    return user;
                }
            }
        }