hi
so I updated to it to test and the issue I described above still persists in 9.2.0. The article you linked is the same one I linked.
Can you share some screenshots?
Have you added the UseAbpTimeZone
middleware?
Thanks.
hi
Tenant will work as expected when tenant claim is set correctly.
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Components;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Owl.reCAPTCHA;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Diagnostics;
using System.Linq;
using System.Security.Claims;
using System.Threading.Tasks;
using Volo.Abp;
using Volo.Abp.Account;
using Volo.Abp.Account.ExternalProviders;
using Volo.Abp.Account.Public.Web;
using Volo.Abp.Account.Public.Web.Pages.Account;
using Volo.Abp.Account.Public.Web.Security.Recaptcha;
using Volo.Abp.Account.Security.Recaptcha;
using Volo.Abp.Account.Settings;
using Volo.Abp.Auditing;
using Volo.Abp.Data;
using Volo.Abp.DependencyInjection;
using Volo.Abp.Identity;
using Volo.Abp.Identity.AspNetCore;
using Volo.Abp.Identity.Settings;
using Volo.Abp.MultiTenancy;
using Volo.Abp.Reflection;
using Volo.Abp.Security.Claims;
using Volo.Abp.Settings;
using Volo.Abp.Uow;
using Volo.Abp.Validation;
using Volo.Saas.Tenants;
using IdentityUser = Volo.Abp.Identity.IdentityUser;
namespace CFData.Structure.Web.Pages.Account;
[DisableAuditing]
[Dependency(ReplaceServices = true)]
[ExposeServices(typeof(MyLoginModel), typeof(LoginModel))]
public class MyLoginModel : LoginModel
{
[Inject]
public ICurrentTenantAccessor CurrentTenantAccessor { get; set; }
[Inject]
public ITenantStore TenantStore { get; set; }
private readonly ITenantRepository _tenantRepository;
protected IDataFilter DataFilter { get; }
public MyLoginModel(
IAuthenticationSchemeProvider schemeProvider,
IOptions accountOptions,
IAbpRecaptchaValidatorFactory recaptchaValidatorFactory,
IAccountExternalProviderAppService accountExternalProviderAppService,
ICurrentPrincipalAccessor currentPrincipalAccessor,
IOptions identityOptions,
IOptionsSnapshot reCaptchaOptions,
ITenantRepository tenantRepository,
DataFilter dataFilter) : base(
schemeProvider,
accountOptions,
recaptchaValidatorFactory,
accountExternalProviderAppService,
currentPrincipalAccessor,
identityOptions,
reCaptchaOptions)
{
//ReCaptchaOptions = reCaptchaOptions;
_tenantRepository = tenantRepository;
DataFilter = dataFilter;
}
public override async Task OnGetAsync()
{
return await base.OnGetAsync();
}
[UnitOfWork] //TODO: Will be removed when we implement action filter
public override async Task OnPostAsync(string action)
{
try
{
await ReCaptchaVerification();
}
catch (UserFriendlyException e)
{
if (e is ScoreBelowThresholdException)
{
var onScoreBelowThresholdResult = OnRecaptchaScoreBelowThreshold();
if (onScoreBelowThresholdResult != null)
{
return await onScoreBelowThresholdResult;
}
}
Alerts.Danger(GetLocalizeExceptionMessage(e));
return Page();
}
//ValidateModel();
await IdentityOptions.SetAsync();
var localLoginResult = await CheckLocalLoginAsync();
if (localLoginResult != null)
{
return localLoginResult;
}
IsSelfRegistrationEnabled = false; //await SettingProvider.IsTrueAsync(AccountSettingNames.IsSelfRegistrationEnabled);
await ReplaceEmailToUsernameOfInputIfNeeds();
var getUser = await FindUserAsync(LoginInput.UserNameOrEmailAddress);
if (getUser == null)
{
Alerts.Danger("User does not exist");
return Page();
}
TenantConfiguration tenant = null;
if (getUser.TenantId is not null)
{
tenant = await TenantStore.FindAsync((Guid)getUser.TenantId);
}
using (CurrentTenant.Change(tenant?.Id))
{
IsLinkLogin = await VerifyLinkTokenAsync();
var result = new Microsoft.AspNetCore.Identity.SignInResult();
using (DataFilter.Disable())
{
result = await SignInManager.PasswordSignInAsync(
LoginInput.UserNameOrEmailAddress,
LoginInput.Password,
LoginInput.RememberMe,
true);
await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext
{
Identity = IdentitySecurityLogIdentityConsts.Identity,
Action = result.ToIdentitySecurityLogAction(),
UserName = LoginInput.UserNameOrEmailAddress
});
}
if (result.RequiresTwoFactor)
{
return RedirectToPage("./SendSecurityCode", new
{
returnUrl = ReturnUrl,
returnUrlHash = ReturnUrlHash,
rememberMe = LoginInput.RememberMe,
linkUserId = LinkUserId,
linkTenantId = LinkTenantId,
linkToken = LinkToken
});
}
if (result.IsLockedOut)
{
var lockedUser = await FindUserAsync(LoginInput.UserNameOrEmailAddress);
await StoreLockedUser(lockedUser);
return RedirectToPage("./LockedOut", new
{
returnUrl = ReturnUrl,
returnUrlHash = ReturnUrlHash
});
}
if (result.IsNotAllowed)
{
var notAllowedUser = await FindUserAsync(LoginInput.UserNameOrEmailAddress);
if (!await UserManager.CheckPasswordAsync(notAllowedUser, LoginInput.Password))
{
Alerts.Danger(L["InvalidUserNameOrPassword"]);
return Page();
}
if (notAllowedUser.ShouldChangePasswordOnNextLogin || await UserManager.ShouldPeriodicallyChangePasswordAsync(notAllowedUser))
{
await StoreChangePasswordUser(notAllowedUser);
return RedirectToPage("./ChangePassword", new
{
returnUrl = ReturnUrl,
returnUrlHash = ReturnUrlHash,
RememberMe = LoginInput.RememberMe
});
}
if (notAllowedUser.IsActive)
{
await StoreConfirmUser(notAllowedUser);
return RedirectToPage("./ConfirmUser", new
{
returnUrl = ReturnUrl,
returnUrlHash = ReturnUrlHash
});
}
Alerts.Danger(L["LoginIsNotAllowed"]);
return Page();
}
if (!result.Succeeded)
{
Alerts.Danger(L["InvalidUserNameOrPassword"]);
return Page();
}
var user = await FindUserAsync(LoginInput.UserNameOrEmailAddress);
if (IsLinkLogin)
{
using (CurrentPrincipalAccessor.Change(await SignInManager.CreateUserPrincipalAsync(user)))
{
await IdentityLinkUserAppService.LinkAsync(new LinkUserInput
{
UserId = LinkUserId.Value,
TenantId = LinkTenantId,
Token = LinkToken
});
await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext
{
Identity = IdentitySecurityLogIdentityConsts.Identity,
Action = IdentityProSecurityLogActionConsts.LinkUser,
UserName = user.UserName,
ExtraProperties =
{
{ IdentityProSecurityLogActionConsts.LinkTargetTenantId, LinkTenantId },
{ IdentityProSecurityLogActionConsts.LinkTargetUserId, LinkUserId }
}
});
using (CurrentTenant.Change(LinkTenantId))
{
var targetUser = await UserManager.GetByIdAsync(LinkUserId.Value);
using (CurrentPrincipalAccessor.Change(await SignInManager.CreateUserPrincipalAsync(targetUser)))
{
await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext
{
Identity = IdentitySecurityLogIdentityConsts.Identity,
Action = IdentityProSecurityLogActionConsts.LinkUser,
UserName = targetUser.UserName,
ExtraProperties =
{
{ IdentityProSecurityLogActionConsts.LinkTargetTenantId, targetUser.TenantId },
{ IdentityProSecurityLogActionConsts.LinkTargetUserId, targetUser.Id }
}
});
}
}
return RedirectToPage("./LinkLogged", new
{
returnUrl = ReturnUrl,
returnUrlHash = ReturnUrlHash,
targetLinkUserId = LinkUserId,
targetLinkTenantId = LinkTenantId
});
}
}
// Clear the dynamic claims cache.
await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(user.Id, user.TenantId);
return await RedirectSafelyAsync(ReturnUrl, ReturnUrlHash);
}
}
protected override async Task ReplaceEmailToUsernameOfInputIfNeeds()
{
if (!ValidationHelper.IsValidEmailAddress(LoginInput.UserNameOrEmailAddress))
{
return;
}
var userByUsername = await FindUserAsync(LoginInput.UserNameOrEmailAddress);
if (userByUsername != null)
{
return;
}
var userByEmail = await FindUserAsync(LoginInput.UserNameOrEmailAddress);
if (userByEmail == null)
{
return;
}
LoginInput.UserNameOrEmailAddress = userByEmail.UserName;
}
protected override async Task GetIdentityUser(string userNameOrEmailAddress)
{
IdentityUser identityUser = null;
using (CurrentTenant.Change(null))
{
identityUser = await base.UserManager.FindByNameAsync(LoginInput.UserNameOrEmailAddress);
if (identityUser == null)
{
identityUser = await base.UserManager.FindByEmailAsync(LoginInput.UserNameOrEmailAddress);
}
}
IdentityUser user = identityUser;
Debug.Assert(user != null, "user != null");
return user;
}
protected virtual async Task FindUserAsync(string uniqueUserNameOrEmailAddress)
{
IdentityUser user = null;
using (CurrentTenant.Change(null))
{
user = await UserManager.FindByNameAsync(LoginInput.UserNameOrEmailAddress) ??
await UserManager.FindByEmailAsync(LoginInput.UserNameOrEmailAddress);
if (user != null)
{
return user;
}
}
foreach (var tenant in await _tenantRepository.GetListAsync())
{
using (CurrentTenant.Change(tenant.Id))
{
user = await UserManager.FindByNameAsync(LoginInput.UserNameOrEmailAddress) ??
await UserManager.FindByEmailAsync(LoginInput.UserNameOrEmailAddress);
if (user != null)
{
return user;
}
}
}
return null;
}
}
hi
Try using Change
method instead of set CurrentTenantAccessor.Current
TenantConfiguration tenant = null;
if (getUser.TenantId is not null)
{
tenant = await TenantStore.FindAsync((Guid)getUser.TenantId);
CurrentTenantAccessor.Current = new BasicTenantInfo(
tenant?.Id,
tenant?.Name);
}
using (CurrentTenant.Change(tenant?.Id))
{
// Add all the code following this to this scope
}
hi
I create the currenttenant is always null/blank even though I'm logged in as the tenant?
What are the claims of your current user?
You can inject the ICurrentUser
and call the GetAllClaims
method.
hi
Can you share your AuthServer
website files from the pods?
You can zip the project files and share them.
Thanks
liming.ma@volosoft.com
hi
Is your code in the AppService layer?
: )
hi
Update MauiProgram
to add .ConfigureContainer(new AbpAutofacServiceProviderFactory(new Autofac.ContainerBuilder()));
will fix the NullReferenceException
namespace Kkd.QueuingService.Maui;
public static class MauiProgram {
public static MauiApp CreateMauiApp() {
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureFonts(fonts => {
fonts.AddFont("OpenSans-Regular.ttf", "OpenSansRegular");
})
.ConfigureContainer(new AbpAutofacServiceProviderFactory(new Autofac.ContainerBuilder()));