abpframework / abp

Open Source Web Application Framework for ASP.NET Core. Offers an opinionated architecture to build enterprise software solutions with best practices on top of the .NET and the ASP.NET Core platforms. Provides the fundamental infrastructure, production-ready startup templates, application modules, UI themes, tooling, guides and documentation.
https://abp.io
GNU Lesser General Public License v3.0
12.31k stars 3.32k forks source link

The instance of entity type 'IdentityUser' cannot be tracked because another instance with the key value #19696

Open abdullahshaqaliah opened 2 weeks ago

abdullahshaqaliah commented 2 weeks ago

Hi I using Abp framework version 8.0.2 I get this error when try login

[21:16:02 ERR] An unhandled exception has occurred while executing the request.
System.InvalidOperationException: The instance of entity type 'IdentityUser' cannot be tracked because another instance with the key value '{Id: 3a120865-c835-6841-3b9c-583f974de8e0}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.

We using the Identity 4 server to log in the error happens when calling this code below

  var result = await SignInManager.PasswordSignInAsync(
      LoginInput.UserNameOrEmailAddress,
      LoginInput.Password,
      LoginInput.RememberMe,
      true
  );

This error happened with some users not for all Can help us to resolve this issue

abdullahshaqaliah commented 2 weeks ago

The log for error

Executing endpoint '/Account/Login'
[21:43:43 INF] Route matched with {page = "/Account/Login", action = "", controller = "", area = ""}. Executing page /Account/Login
[21:43:43 INF] Skipping the execution of current filter as its not the most effective filter implementing the policy Microsoft.AspNetCore.Mvc.ViewFeatures.IAntiforgeryPolicy
[21:43:45 INF] Executing handler method Volo.Abp.Account.Web.Pages.Account.LoginModel.OnPostAsync - ModelState is Valid
[21:43:45 WRN] Sensitive data logging is enabled. Log entries and exception messages may include sensitive application data; this mode should only be enabled during development.
[21:43:48 INF] Executed DbCommand (448ms) [Parameters=[@__ef_filter__p_0='False', @__ef_filter__p_1='False', @__NormalizeName_0='HANA.ABD-ELJAWAD@TENTIMEJO.COM', @__NormalizeEmail_1='HANA.ABD-ELJAWAD@TENTIMEJO.COM', @__NormalizePhoneNumber_2='HANA.ABD-ELJAWAD@TENTIMEJO.COM'], CommandType='Text', CommandTimeout='30']
SELECT u."Id", u."AccessFailedCount", u."ConcurrencyStamp", u."CreationTime", u."CreatorId", u."DeleterId", u."DeletionTime", u."Email", u."EmailConfirmed", u."EntityVersion", u."ExtraProperties", u."IsActive", u."IsDeleted", u."IsExternal", u."LastModificationTime", u."LastModifierId", u."LastPasswordChangeTime", u."LockoutEnabled", u."LockoutEnd", u."Name", u."NormalizedEmail", u."NormalizedUserName", u."ParentalLockCode", u."PasswordHash", u."PhoneNumber", u."PhoneNumberConfirmed", u."RestrictMainProfileAccess", u."RestrictManagingProfiles", u."SecurityStamp", u."ShouldChangePasswordOnNextLogin", u."Surname", u."TenantId", u."TwoFactorEnabled", u."UserName"
FROM "Users" AS u
WHERE (@__ef_filter__p_0 OR NOT (u."IsDeleted")) AND (@__ef_filter__p_1 OR u."TenantId" IS NULL) AND (u."NormalizedUserName" = @__NormalizeName_0 OR u."NormalizedEmail" = @__NormalizeEmail_1 OR u."PhoneNumber" = @__NormalizePhoneNumber_2)
ORDER BY u."Id"
LIMIT 1
[21:43:48 INF] Executed DbCommand (398ms) [Parameters=[@__ef_filter__p_0='False', @__ef_filter__p_1='False', @__NormalizeName_0='HANA.ABD-ELJAWAD@TENTIMEJO.COM', @__NormalizeEmail_1='HANA.ABD-ELJAWAD@TENTIMEJO.COM', @__NormalizePhoneNumber_2='HANA.ABD-ELJAWAD@TENTIMEJO.COM'], CommandType='Text', CommandTimeout='30']
SELECT u."Id", u."AccessFailedCount", u."ConcurrencyStamp", u."CreationTime", u."CreatorId", u."DeleterId", u."DeletionTime", u."Email", u."EmailConfirmed", u."EntityVersion", u."ExtraProperties", u."IsActive", u."IsDeleted", u."IsExternal", u."LastModificationTime", u."LastModifierId", u."LastPasswordChangeTime", u."LockoutEnabled", u."LockoutEnd", u."Name", u."NormalizedEmail", u."NormalizedUserName", u."ParentalLockCode", u."PasswordHash", u."PhoneNumber", u."PhoneNumberConfirmed", u."RestrictMainProfileAccess", u."RestrictManagingProfiles", u."SecurityStamp", u."ShouldChangePasswordOnNextLogin", u."Surname", u."TenantId", u."TwoFactorEnabled", u."UserName"
FROM "Users" AS u
WHERE (@__ef_filter__p_0 OR NOT (u."IsDeleted")) AND (@__ef_filter__p_1 OR u."TenantId" IS NULL) AND (u."NormalizedUserName" = @__NormalizeName_0 OR u."NormalizedEmail" = @__NormalizeEmail_1 OR u."PhoneNumber" = @__NormalizePhoneNumber_2)
ORDER BY u."Id"
LIMIT 1
[21:43:49 INF] Executed DbCommand (383ms) [Parameters=[@__ef_filter__p_0='False', @__ef_filter__p_1='False', @__NormalizeName_0='HANA', @__NormalizeEmail_1='HANA', @__NormalizePhoneNumber_2='HANA'], CommandType='Text', CommandTimeout='30']
SELECT u."Id", u."AccessFailedCount", u."ConcurrencyStamp", u."CreationTime", u."CreatorId", u."DeleterId", u."DeletionTime", u."Email", u."EmailConfirmed", u."EntityVersion", u."ExtraProperties", u."IsActive", u."IsDeleted", u."IsExternal", u."LastModificationTime", u."LastModifierId", u."LastPasswordChangeTime", u."LockoutEnabled", u."LockoutEnd", u."Name", u."NormalizedEmail", u."NormalizedUserName", u."ParentalLockCode", u."PasswordHash", u."PhoneNumber", u."PhoneNumberConfirmed", u."RestrictMainProfileAccess", u."RestrictManagingProfiles", u."SecurityStamp", u."ShouldChangePasswordOnNextLogin", u."Surname", u."TenantId", u."TwoFactorEnabled", u."UserName"
FROM "Users" AS u
WHERE (@__ef_filter__p_0 OR NOT (u."IsDeleted")) AND (@__ef_filter__p_1 OR u."TenantId" IS NULL) AND (u."NormalizedUserName" = @__NormalizeName_0 OR u."NormalizedEmail" = @__NormalizeEmail_1 OR u."PhoneNumber" = @__NormalizePhoneNumber_2)
ORDER BY u."Id"
LIMIT 1
[21:43:49 INF] Executed DbCommand (416ms) [Parameters=[@__ef_filter__p_0='False', @__ef_filter__p_1='False', @__normalizedEmail_0='HANA.ABD-ELJAWAD@TENTIMEJO.COM'], CommandType='Text', CommandTimeout='30']
SELECT u."Id", u."AccessFailedCount", u."ConcurrencyStamp", u."CreationTime", u."CreatorId", u."DeleterId", u."DeletionTime", u."Email", u."EmailConfirmed", u."EntityVersion", u."ExtraProperties", u."IsActive", u."IsDeleted", u."IsExternal", u."LastModificationTime", u."LastModifierId", u."LastPasswordChangeTime", u."LockoutEnabled", u."LockoutEnd", u."Name", u."NormalizedEmail", u."NormalizedUserName", u."ParentalLockCode", u."PasswordHash", u."PhoneNumber", u."PhoneNumberConfirmed", u."RestrictMainProfileAccess", u."RestrictManagingProfiles", u."SecurityStamp", u."ShouldChangePasswordOnNextLogin", u."Surname", u."TenantId", u."TwoFactorEnabled", u."UserName"
FROM "Users" AS u
WHERE (@__ef_filter__p_0 OR NOT (u."IsDeleted")) AND (@__ef_filter__p_1 OR u."TenantId" IS NULL) AND u."NormalizedEmail" = @__normalizedEmail_0
ORDER BY u."Id"
LIMIT 1
[21:43:50 INF] Executed DbCommand (281ms) [Parameters=[@__ef_filter__p_0='False', @__ef_filter__p_1='False', @__normalizedEmail_0='HANA'], CommandType='Text', CommandTimeout='30']
SELECT u."Id", u."AccessFailedCount", u."ConcurrencyStamp", u."CreationTime", u."CreatorId", u."DeleterId", u."DeletionTime", u."Email", u."EmailConfirmed", u."EntityVersion", u."ExtraProperties", u."IsActive", u."IsDeleted", u."IsExternal", u."LastModificationTime", u."LastModifierId", u."LastPasswordChangeTime", u."LockoutEnabled", u."LockoutEnd", u."Name", u."NormalizedEmail", u."NormalizedUserName", u."ParentalLockCode", u."PasswordHash", u."PhoneNumber", u."PhoneNumberConfirmed", u."RestrictMainProfileAccess", u."RestrictManagingProfiles", u."SecurityStamp", u."ShouldChangePasswordOnNextLogin", u."Surname", u."TenantId", u."TwoFactorEnabled", u."UserName"
FROM "Users" AS u
WHERE (@__ef_filter__p_0 OR NOT (u."IsDeleted")) AND (@__ef_filter__p_1 OR u."TenantId" IS NULL) AND u."NormalizedEmail" = @__normalizedEmail_0
ORDER BY u."Id"
LIMIT 1
[21:43:53 ERR] ---------- RemoteServiceErrorInfo ----------
{
  "code": null,
  "message": "An internal error occurred during your request!",
  "details": null,
  "data": {},
  "validationErrors": null
}

[21:43:53 ERR] The instance of entity type 'IdentityUser' cannot be tracked because another instance with the key value '{Id: 3a120865-c835-6841-3b9c-583f974de8e0}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.
System.InvalidOperationException: The instance of entity type 'IdentityUser' cannot be tracked because another instance with the key value '{Id: 3a120865-c835-6841-3b9c-583f974de8e0}' is already being tracked. When attaching existing entities, ensure that only one entity instance with a given key value is attached.
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.ThrowIdentityConflict(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(TKey key, InternalEntityEntry entry, Boolean updateDuplicate)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(TKey key, InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.IdentityMap`1.Add(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.StateManager.StartTracking(InternalEntityEntry entry)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState oldState, EntityState newState, Boolean acceptChanges, Boolean modifyProperties)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.InternalEntityEntry.SetEntityState(EntityState entityState, Boolean acceptChanges, Boolean modifyProperties, Nullable`1 forceStateWhenUnknownKey, Nullable`1 fallbackState)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.PaintAction(EntityEntryGraphNode`1 node)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityEntryGraphIterator.TraverseGraph[TState](EntityEntryGraphNode`1 node, Func`2 handleNode)
   at Microsoft.EntityFrameworkCore.ChangeTracking.Internal.EntityGraphAttacher.AttachGraph(InternalEntityEntry rootEntry, EntityState targetState, EntityState storeGeneratedWithKeySetTargetState, Boolean forceStateWhenUnknownKey)
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.SetEntityState(InternalEntityEntry entry, EntityState entityState)
   at Microsoft.EntityFrameworkCore.Internal.InternalDbSet`1.Attach(TEntity entity)
   at Volo.Abp.Domain.Repositories.EntityFrameworkCore.EfCoreRepository`2.UpdateAsync(TEntity entity, Boolean autoSave, CancellationToken cancellationToken)
   at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
   at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
   at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
   at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
   at Volo.Abp.Identity.IdentityUserStore.UpdateAsync(IdentityUser user, CancellationToken cancellationToken)
   at Microsoft.AspNetCore.Identity.UserManager`1.UpdateUserAsync(TUser user)
   at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
   at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
   at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
   at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
   at Microsoft.AspNetCore.Identity.UserManager`1.ResetAccessFailedCountAsync(TUser user)
   at Castle.DynamicProxy.AsyncInterceptorBase.ProceedAsynchronous[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo)
   at Volo.Abp.Castle.DynamicProxy.CastleAbpMethodInvocationAdapterWithReturnValue`1.ProceedAsync()
   at Volo.Abp.Uow.UnitOfWorkInterceptor.InterceptAsync(IAbpMethodInvocation invocation)
   at Volo.Abp.Castle.DynamicProxy.CastleAsyncAbpInterceptorAdapter`1.InterceptAsync[TResult](IInvocation invocation, IInvocationProceedInfo proceedInfo, Func`3 proceed)
   at Microsoft.AspNetCore.Identity.SignInManager`1.ResetLockout(TUser user)
   at Microsoft.AspNetCore.Identity.SignInManager`1.ResetLockoutWithResult(TUser user)
   at Microsoft.AspNetCore.Identity.SignInManager`1.CheckPasswordSignInAsync(TUser user, String password, Boolean lockoutOnFailure)
   at Microsoft.AspNetCore.Identity.SignInManager`1.PasswordSignInAsync(TUser user, String password, Boolean isPersistent, Boolean lockoutOnFailure)
   at Microsoft.AspNetCore.Identity.SignInManager`1.PasswordSignInAsync(String userName, String password, Boolean isPersistent, Boolean lockoutOnFailure)
   at Volo.Abp.Identity.AspNetCore.AbpSignInManager.PasswordSignInAsync(String userName, String password, Boolean isPersistent, Boolean lockoutOnFailure)
   at TenTime.IdentityServer.Pages.Account.IdentityServerLoginModel.OnPostAsync(String action) in F:\TenTimeWork\Applications\authentication_server\src\TenTime.IdentityServer\Pages\Account\IdentityServerLoginModel.cs:line 157
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory.GenericTaskHandlerMethod.Convert[T](Object taskAsObject)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.ExecutorFactory.GenericTaskHandlerMethod.Execute(Object receiver, Object[] arguments)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeHandlerMethodAsync()
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeNextPageFilterAsync()
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Rethrow(PageHandlerExecutedContext context)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)
   at Microsoft.AspNetCore.Mvc.RazorPages.Infrastructure.PageActionInvoker.InvokeInnerFilterAsync()
   at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeNextExceptionFilterAsync>g__Awaited|26_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)
maliming commented 2 weeks ago

hi

Please share the code of IdentityServerLoginModel class.

abdullahshaqaliah commented 2 weeks ago

`using IdentityServer4.Events; using IdentityServer4.Models; using IdentityServer4.Services; using IdentityServer4.Stores; using Microsoft.AspNetCore.Authentication; using Microsoft.AspNetCore.Identity; using Microsoft.AspNetCore.Mvc; using Microsoft.Extensions.Logging; using Microsoft.Extensions.Options; using System; using System.Diagnostics; using System.Linq; using System.Security.Claims; using System.Threading.Tasks; using TenTime.IdentityServer.AspNetIdentity; using TenTime.IdentityServer.Mtv; using TenTime.IdentityService.Identity; using Volo.Abp; using Volo.Abp.Account.Settings; using Volo.Abp.Account.Web; using Volo.Abp.Account.Web.Pages.Account; using Volo.Abp.AspNetCore.Mvc.UI.Theming; using Volo.Abp.DependencyInjection; using Volo.Abp.Identity; using Volo.Abp.Identity.AspNetCore; using Volo.Abp.MultiTenancy; using Volo.Abp.Security.Claims; using Volo.Abp.Settings; using IdentityUser = Volo.Abp.Identity.IdentityUser;

namespace TenTime.IdentityServer.Pages.Account; [ExposeServices(typeof(LoginModel))]

public class IdentityServerLoginModel : IdentityServerSupportedLoginModel { private readonly MtvOptions _mtvOptions;

private readonly TenTimeUserManager _userManager;

private string _externalProvider = "external_provider";
private readonly ILinkAccountRepository _linkAccountRepository;

public IdentityServerLoginModel(IAuthenticationSchemeProvider schemeProvider, IOptions<AbpAccountOptions> accountOptions, IOptions<IdentityOptions> identityOptions, IdentityDynamicClaimsPrincipalContributorCache identityDynamicClaimsPrincipalContributorCache, IIdentityServerInteractionService interaction, IClientStore clientStore, IEventService identityServerEvents,
    IOptions<MtvOptions> mtvOptions = null,
    TenTimeUserManager userManager = null, ILinkAccountRepository linkAccountRepository = null) : base(schemeProvider, accountOptions, identityOptions, identityDynamicClaimsPrincipalContributorCache, interaction, clientStore, identityServerEvents)
{
    _mtvOptions = mtvOptions.Value;
    _userManager = userManager;
    _linkAccountRepository = linkAccountRepository;
}

public override async Task<IActionResult> OnGetAsync()
{

    LoginInput = new LoginInputModel();

    var context = await Interaction.GetAuthorizationContextAsync(ReturnUrl);

    if (context != null)
    {
        // TODO: Find a proper cancel way.
        // ShowCancelButton = true;

        LoginInput.UserNameOrEmailAddress = context.LoginHint;

        //TODO: Reference AspNetCore MultiTenancy module and use options to get the tenant key!
        var tenant = context.Parameters[TenantResolverConsts.DefaultTenantKey];
        if (!string.IsNullOrEmpty(tenant))
        {
            CurrentTenant.Change(Guid.Parse(tenant));
            Response.Cookies.Append(TenantResolverConsts.DefaultTenantKey, tenant);
        }

        var externalProviderLogin = context.Parameters.Get(_externalProvider);
        if (!externalProviderLogin.IsNullOrWhiteSpace())
        {
            if (await SchemeProvider.GetSchemeAsync(externalProviderLogin).ConfigureAwait(false) != null)
            {
                return await base.OnPostExternalLogin(externalProviderLogin);
            }
        }

    }

    if (context?.IdP != null)
    {

        LoginInput.UserNameOrEmailAddress = context.LoginHint;
        ExternalProviders = new[] { new ExternalProviderModel { AuthenticationScheme = context.IdP } };
        return Page();
    }

    var providers = await GetExternalProviders();
    ExternalProviders = providers.ToList();

    EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin);

    if (context?.Client?.ClientId != null)
    {
        var client = await ClientStore.FindEnabledClientByIdAsync(context?.Client?.ClientId);
        if (client != null)
        {
            EnableLocalLogin = client.EnableLocalLogin;

            if (client.IdentityProviderRestrictions != null && client.IdentityProviderRestrictions.Any())
            {
                providers = providers.Where(provider => client.IdentityProviderRestrictions.Contains(provider.AuthenticationScheme)).ToList();
            }
        }
    }

    if (IsExternalLoginOnly)
    {
        return await base.OnPostExternalLogin(providers.First().AuthenticationScheme);
    }

    return Page();
}
public override async Task<IActionResult> OnPostAsync(string action)
{
    var context = await Interaction.GetAuthorizationContextAsync(ReturnUrl);
    if (action == "Cancel")
    {
        if (context == null)
        {
            return Redirect("~/");
        }

        await Interaction.GrantConsentAsync(context, new ConsentResponse()
        {
            Error = AuthorizationError.AccessDenied
        });

        return Redirect(ReturnUrl);
    }

    await CheckLocalLoginAsync();

    ValidateModel();

    await IdentityOptions.SetAsync();

    ExternalProviders = await GetExternalProviders();

    EnableLocalLogin = await SettingProvider.IsTrueAsync(AccountSettingNames.EnableLocalLogin);

    await ReplaceEmailToUsernameOfInputIfNeeds();

    var 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,
        ClientId = context?.Client?.ClientId
    });

    if (result.RequiresTwoFactor)
    {
        return await TwoFactorLoginResultAsync();
    }

    if (result.IsLockedOut)
    {
        Alerts.Warning(L["UserLockedOutMessage"]);
        return Page();
    }

    if (result.IsNotAllowed)
    {
        Alerts.Warning(L["LoginIsNotAllowed"]);
        return Page();
    }

    if (!result.Succeeded)
    {
        Alerts.Danger(L["InvalidUserNameOrPassword"]);
        return Page();
    }

    //TODO: Find a way of getting user's id from the logged in user and do not query it again like that!
    var user = await _userManager.FindByAccountAsync(LoginInput.UserNameOrEmailAddress).ConfigureAwait(false);

    Debug.Assert(user != null, nameof(user) + " != null");
    await IdentityServerEvents.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id.ToString(), user.UserName)); //TODO: Use user's name once implemented
                                                                                                                        // Clear the dynamic claims cache.
    await IdentityDynamicClaimsPrincipalContributorCache.ClearAsync(user.Id, user.TenantId);
    return  await RedirectSafelyAsync(ReturnUrl, ReturnUrlHash);
}

protected  async Task<IdentityUser> CreateExternalUserAsync(ExternalLoginInfo info)
{
    await IdentityOptions.SetAsync();

    var emailAddress = info.Principal.FindFirstValue(AbpClaimTypes.Email) ?? info.Principal.Identities.First().FindFirst(ClaimTypes.Email)?.Value;

    //var emailAddress = info.Principal.FindFirstValue(AbpClaimTypes.Email);

    var user = new IdentityUser(GuidGenerator.Create(), emailAddress, emailAddress, CurrentTenant.Id);

    CheckIdentityErrors(await UserManager.CreateAsync(user));
    CheckIdentityErrors(await UserManager.SetEmailAsync(user, emailAddress));
    CheckIdentityErrors(await UserManager.AddLoginAsync(user, info));
    CheckIdentityErrors(await UserManager.AddDefaultRolesAsync(user));

    user.Name = info.Principal.FindFirstValue(AbpClaimTypes.Name);
    user.Surname = info.Principal.FindFirstValue(AbpClaimTypes.SurName);
    user.SetEmailConfirmed(true);
    user.IsExternal = true;
    var phoneNumber = info.Principal.FindFirstValue(AbpClaimTypes.PhoneNumber);
    if (!phoneNumber.IsNullOrWhiteSpace())
    {
        var phoneNumberConfirmed = string.Equals(info.Principal.FindFirstValue(AbpClaimTypes.PhoneNumberVerified), "true", StringComparison.InvariantCultureIgnoreCase);
        user.SetPhoneNumber(phoneNumber, phoneNumberConfirmed);
    }

    await UserManager.UpdateAsync(user);

    return user;
}
public override async Task<IActionResult> OnGetExternalLoginCallbackAsync(string returnUrl = "", string returnUrlHash = "", string remoteError = null)
{
    //TODO: Did not implemented Identity Server 4 sample for this method (see ExternalLoginCallback in Quickstart of IDS4 sample)
    /* Also did not implement these:
     * - Logout(string logoutId)
     */

    if (remoteError != null)
    {
        Logger.LogWarning($"External login callback error: {remoteError}");
        return RedirectToPage("./Login");
    }

    await IdentityOptions.SetAsync();

    var loginInfo = await SignInManager.GetExternalLoginInfoAsync();
    if (loginInfo == null)
    {
        Logger.LogWarning("External login info is not available");
        return RedirectToPage("./Login");
    }

    var result = await SignInManager.ExternalLoginSignInAsync(
        loginInfo.LoginProvider,
        loginInfo.ProviderKey,
        isPersistent: false,
        bypassTwoFactor: true
    );

    if (!result.Succeeded)
    {
        await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext()
        {
            Identity = IdentitySecurityLogIdentityConsts.IdentityExternal,
            Action = "Login" + result
        });
    }

    if (result.IsLockedOut)
    {
        Logger.LogWarning($"External login callback error: user is locked out!");
        throw new UserFriendlyException("Cannot proceed because user is locked out!");
    }

    if (result.IsNotAllowed)
    {
        Logger.LogWarning($"External login callback error: user is not allowed!");
        throw new UserFriendlyException("Cannot proceed because user is not allowed!");
    }

    if (result.Succeeded)
    {
        return await RedirectSafelyAsync(returnUrl, returnUrlHash);
    }

    //TODO: Handle other cases for result!

    var email = loginInfo.Principal.FindFirstValue(AbpClaimTypes.Email) ?? loginInfo.Principal.Identities.First().FindFirst(ClaimTypes.Email)?.Value;
    if (email.IsNullOrWhiteSpace())
    {
        Logger.LogWarning("External login info is not available");
        return RedirectToPage("./Login");
        //return RedirectToPage("./Register", new
        //{
        //    IsExternalLogin = true,
        //    ExternalLoginAuthSchema = loginInfo.LoginProvider,
        //    ReturnUrl = returnUrl
        //});
        //var identity = loginInfo.Principal.Identities.First();
        //var emailClaim = identity.FindFirst(ClaimTypes.Email);

        //if (emailClaim == null)
        //{
        //    Logger.LogWarning("External login info is not available");
        //    return RedirectToPage("./Login");
        //}
        //email = emailClaim.Value;
    }
    IdentityUser user;
    var linkAccount = await _linkAccountRepository.GetAsync(loginInfo.LoginProvider, email).ConfigureAwait(false);
    if (linkAccount == null)
    {
         user = await UserManager.FindByEmailAsync(email);
        if (user == null)
        {
            user = await CreateExternalUserAsync(loginInfo);
        }
        else
        {
            if (await UserManager.FindByLoginAsync(loginInfo.LoginProvider, loginInfo.ProviderKey) == null)
            {
                CheckIdentityErrors(await UserManager.AddLoginAsync(user, loginInfo));
            }
        }
    }
    else
    {
        user = await _userManager.FindByIdAsync(linkAccount.UserId.ToString()).ConfigureAwait(false);

    }

    await SignInManager.SignInAsync(user, false);

    await IdentitySecurityLogManager.SaveAsync(new IdentitySecurityLogContext()
    {
        Identity = IdentitySecurityLogIdentityConsts.IdentityExternal,
        Action = result.ToIdentitySecurityLogAction(),
        UserName = user.Name
    });
    return await RedirectSafelyAsync(returnUrl, returnUrlHash);
}

public override async Task<IActionResult> OnPostExternalLogin(string provider)
{
    var redirectUrl = Url.Page("./LoginMtv", values: new { ReturnUrl, ReturnUrlHash });

    if (provider== _mtvOptions.LoginProvider)
    {
        return await Task.FromResult(Redirect(redirectUrl));
    }

    return await base.OnPostExternalLogin(provider).ConfigureAwait(false);
}

}

`

I resolved the issue by overriding two method on the class SignInManager to stop this issue the problem with checking whether the user has a locked account or not `public class TenTimeSignInManager : AbpSignInManager { public TenTimeSignInManager(IdentityUserManager userManager, IHttpContextAccessor contextAccessor, IUserClaimsPrincipalFactory claimsFactory, IOptions optionsAccessor, ILogger<SignInManager> logger, IAuthenticationSchemeProvider schemes, IUserConfirmation confirmation, IOptions options, ISettingProvider settingProvider) : base(userManager, contextAccessor, claimsFactory, optionsAccessor, logger, schemes, confirmation, options, settingProvider) { }

protected override  Task ResetLockout(Volo.Abp.Identity.IdentityUser user)
{
    return Task.CompletedTask;
}
public override async Task<SignInResult> CheckPasswordSignInAsync(Volo.Abp.Identity.IdentityUser user, string password, bool lockoutOnFailure)
{
    ArgumentNullException.ThrowIfNull(user);

    var error = await PreSignInCheck(user);
    if (error != null)
    {
        return error;
    }

    if (await UserManager.CheckPasswordAsync(user, password))
    {
        var alwaysLockout = AppContext.TryGetSwitch("Microsoft.AspNetCore.Identity.CheckPasswordSignInAlwaysResetLockoutOnSuccess", out var enabled) && enabled;
        // Only reset the lockout when not in quirks mode if either TFA is not enabled or the client is remembered for TFA.
        if (alwaysLockout || !await IsTwoFactorEnabledAsync(user) || await IsTwoFactorClientRememberedAsync(user))
        {
            var resetLockoutResult = await ResetLockoutWithResult(user);
            if (!resetLockoutResult.Succeeded)
            {
                // ResetLockout got an unsuccessful result that could be caused by concurrency failures indicating an
                // attacker could be trying to bypass the MaxFailedAccessAttempts limit. Return the same failure we do
                // when failing to increment the lockout to avoid giving an attacker extra guesses at the password.
                return SignInResult.Failed;
            }
        }

        return SignInResult.Success;
    }
    //Logger.LogDebug(EventIds.InvalidPassword, "User failed to provide the correct password.");

    if (UserManager.SupportsUserLockout && lockoutOnFailure)
    {
        // If lockout is requested, increment access failed count which might lock out the user
        var incrementLockoutResult = /*await UserManager.AccessFailedAsync(user) ??*/ IdentityResult.Success;
        if (!incrementLockoutResult.Succeeded)
        {
            // Return the same failure we do when resetting the lockout fails after a correct password.
            return SignInResult.Failed;
        }

        if (await UserManager.IsLockedOutAsync(user))
        {
            return await LockedOut(user);
        }
    }
    return SignInResult.Failed;
}

private async Task<IdentityResult> ResetLockoutWithResult(Volo.Abp.Identity.IdentityUser user)
{
    // Avoid relying on throwing an exception if we're not in a derived class.
    if (GetType() == typeof(SignInManager<Volo.Abp.Identity.IdentityUser>))
    {
        if (!UserManager.SupportsUserLockout)
        {
            return IdentityResult.Success;
        }

        return await UserManager.ResetAccessFailedCountAsync(user) ?? IdentityResult.Success;
    }

    var resetLockoutTask = ResetLockout(user);

    if (resetLockoutTask is Task<IdentityResult> resultTask)
    {
        return await resultTask ?? IdentityResult.Success;
    }

    await resetLockoutTask;
    return IdentityResult.Success;
    //try
    //{
    //    var resetLockoutTask = ResetLockout(user);

    //    if (resetLockoutTask is Task<IdentityResult> resultTask)
    //    {
    //        return await resultTask ?? IdentityResult.Success;
    //    }

    //    await resetLockoutTask;
    //    return IdentityResult.Success;
    //}
    //catch (IdentityResultException ex)
    //{
    //    return ex.IdentityResult;
    //}
}

} ` The problem with methods ResetLockout and UserManager.AccessFailedAsync(user)

maliming commented 1 week ago

How can I reproduce this in a new template project? Or can you share a simple project?