External Authentication does not work sometime when user does not exist
See original GitHub issueI using ABP framework for my project. It is AspCore + Angular target Full .Net framework. I am using External Authentication for login. I have followed the steps mentioned in the document. I have configured it to use Windows Authentication which works fine when the user already exists in the DB. I noticed that when it is the first time that user is visiting the website it gently registers the user and then authenticates it into the system. For some reason sometimes when it is the first time that user is visiting the website it throws an error. After like 10-20 refresh it works fine sometimes. Interestingly when it finally goes in after several page refresh the user id jumps from the latest which (e.g. user id 6) to user id 10000 or from 10004 to 20000.
Here is the error in the log:
INFO 2018-05-15 11:19:54,995 [13 ] ore.Mvc.Internal.ControllerActionInvoker - Executing action method SAH.NEO.Controllers.TokenAuthController.Authenticate (SAH.NEO.Web.Core) with arguments (SAH.NEO.Models.TokenAuth.AuthenticateModel) - ModelState is Valid ERROR 2018-05-15 11:19:55,042 [9 ] Mvc.ExceptionHandling.AbpExceptionFilter - There is no such an entity. Entity type: SAH.NEO.Authorization.Users.User, id: 9 Abp.Domain.Entities.EntityNotFoundException: There is no such an entity. Entity type: SAH.NEO.Authorization.Users.User, id: 9 at Abp.Domain.Repositories.AbpRepositoryBase2.<GetAsync>d__21.MoveNext() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Abp.Threading.InternalAsyncHelper.<AwaitTaskWithPostActionAndFinallyAndGetResult>d__51.MoveNext() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Abp.Authorization.Users.AbpUserStore2.<GetUserNameFromDatabaseAsync>d__88.MoveNext() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Abp.Authorization.Users.AbpUserManager2.d__47.MoveNext() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Abp.Authorization.AbpLogInManager3.<CreateLoginResultAsync>d__38.MoveNext() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task) at Abp.Authorization.AbpLogInManager3.d__37.MoveNext() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Abp.Authorization.AbpLogInManager3.<LoginAsync>d__36.MoveNext() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Abp.Threading.InternalAsyncHelper.<AwaitTaskWithPostActionAndFinallyAndGetResult>d__51.MoveNext() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Nito.AsyncEx.Synchronous.TaskExtensions.WaitAndUnwrapException[TResult](Task1 task) at Nito.AsyncEx.AsyncContext.<>c__DisplayClass16_01.b__0(Task1 t) at System.Threading.Tasks.ContinuationResultTaskFromResultTask2.InnerInvoke() at System.Threading.Tasks.Task.Execute() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Nito.AsyncEx.Synchronous.TaskExtensions.WaitAndUnwrapException[TResult](Task1 task) at Nito.AsyncEx.AsyncContext.Run[TResult](Func1 action) at Abp.Threading.AsyncHelper.RunSync[TResult](Func1 func) at Abp.Authorization.AbpLogInManagerExtensions.Login[TTenant,TRole,TUser](AbpLogInManager3 logInManager, String userNameOrEmailAddress, String plainPassword, String tenancyName, Boolean shouldLockout) at SAH.NEO.Controllers.TokenAuthController.GetLoginResult(String usernameOrEmailAddress, String password, String tenancyName) in C:\Projects\NEO\Main\SAH.NEO\src\SAH.NEO.Web.Core\Controllers\TokenAuthController.cs:line 197 at SAH.NEO.Controllers.TokenAuthController.d__8.MoveNext() in C:\Projects\NEO\Main\SAH.NEO\src\SAH.NEO.Web.Core\Controllers\TokenAuthController.cs:line 57 β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at lambda_method(Closure , Object ) at Microsoft.Extensions.Internal.ObjectMethodExecutorAwaitable.Awaiter.GetResult() at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__12.MoveNext() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__10.MoveNext() β End of stack trace from previous location where exception was thrown β at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Rethrow(ActionExecutedContext context) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker.d__14.MoveNext() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Mvc.Internal.ResourceInvoker.d__23.MoveNext() INFO 2018-05-15 11:19:55,042 [9 ] etCore.Mvc.Internal.ObjectResultExecutor - Executing ObjectResult, writing value Microsoft.AspNetCore.Mvc.ControllerContext. INFO 2018-05-15 11:19:55,042 [9 ] ore.Mvc.Internal.ControllerActionInvoker - Executed action SAH.NEO.Controllers.TokenAuthController.Authenticate (SAH.NEO.Web.Core) in 52.0181ms ERROR 2018-05-15 11:19:55,042 [9 ] Microsoft.AspNetCore.Server.Kestrel - Connection id β0HLDQ0BD8TOQAβ, Request id β0HLDQ0BD8TOQA:00000003β: An unhandled exception was thrown by the application. System.InvalidOperationException: StatusCode cannot be set because the response has already started. at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Frame.set_StatusCode(Int32 value) at Microsoft.AspNetCore.Server.Kestrel.Core.Internal.Http.Frame.Microsoft.AspNetCore.Http.Features.IHttpResponseFeature.set_StatusCode(Int32 value) at Microsoft.AspNetCore.Http.Internal.DefaultHttpResponse.set_StatusCode(Int32 value) at Microsoft.AspNetCore.Builder.Internal.ApplicationBuilder.<>c.b__16_0(HttpContext context) at Microsoft.AspNetCore.StaticFiles.StaticFileMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.StaticFiles.DefaultFilesMiddleware.Invoke(HttpContext context) at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.d__6.MoveNext() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Builder.RouterMiddleware.d__4.MoveNext() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.Owin.Mapping.MapMiddleware.d__0.MoveNext() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Owin.WebSocketAcceptAdapter.<>c__DisplayClass6_0.<b__0>d.MoveNext() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Localization.RequestLocalizationMiddleware.d__4.MoveNext() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.d__6.MoveNext() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at SAH.NEO.Web.Host.Startup.Startup.<>c.<b__4_1>d.MoveNext() in C:\Projects\NEO\Main\SAH.NEO\src\SAH.NEO.Web.Host\Startup\Startup.cs:line 124 β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.d__7.MoveNext() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Abp.AspNetCore.Security.AbpSecurityHeadersMiddleware.d__2.MoveNext() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Server.IISIntegration.IISMiddleware.d__11.MoveNext() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at Microsoft.AspNetCore.Hosting.Internal.RequestServicesContainerMiddleware.d__3.MoveNext() β End of stack trace from previous location where exception was thrown β at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) at System.Runtime.CompilerServices.TaskAwaiter.ValidateEnd(Task task)
I have changed the GetLoginResultAsync
to sync method as I thought it might be this that sometime works sometime does not but it was not it.
Issue Analytics
- State:
- Created 5 years ago
- Comments:37 (12 by maintainers)
Top GitHub Comments
I have taken a deeper look at the issue. This seems to be a problem when using
UnitOfWork.IsTransactional
withPostgreSQL
When a new user is created via
AbpLoginManager.TryLoginFromExternalAuthenticationSources()
. https://github.com/aspnetboilerplate/aspnetboilerplate/blob/cf87dd654bab699dbb5962003efd55ac945e3e2c/src/Abp.ZeroCore/Authorization/AbpLoginManager.cs#L307-L323The user entity is being tracked in
Microsoft.EntityFrameworkCore.ChangeTracker.Entries()
afterSaveChangesAsync()
is called followed byawait UserManager.CreateAsync(user);
.However, the user is then updated in
CreateLoginResultAsync()
after the entity creation while it is still under the same transaction. https://github.com/aspnetboilerplate/aspnetboilerplate/blob/cf87dd654bab699dbb5962003efd55ac945e3e2c/src/Abp.ZeroCore/Authorization/AbpLoginManager.cs#L170-L201https://github.com/aspnetboilerplate/aspnetboilerplate/blob/cf87dd654bab699dbb5962003efd55ac945e3e2c/src/Abp.ZeroCore/Authorization/AbpLoginManager.cs#L205-L234
The exception is thrown when
UserManager.UpdateAsync(user)
checks for old username from database. https://github.com/aspnetboilerplate/aspnetboilerplate/blob/cf87dd654bab699dbb5962003efd55ac945e3e2c/src/Abp.ZeroCore/Authorization/Users/AbpUserManager.cs#L613And a new scope is used to retrieve old username https://github.com/aspnetboilerplate/aspnetboilerplate/blob/cf87dd654bab699dbb5962003efd55ac945e3e2c/src/Abp.ZeroCore/Authorization/Users/AbpUserStore.cs#L1221-L1232
By default,
EfCoreUnitOfWork
usesIsolationLevel.ReadUncommitted
but it is treated asIsolationLevel.ReadCommitted
inPostgreSQL
https://github.com/aspnetboilerplate/aspnetboilerplate/blob/cf87dd654bab699dbb5962003efd55ac945e3e2c/src/Abp.EntityFrameworkCore/EntityFrameworkCore/Uow/DbContextEfCoreTransactionStrategy.cs#L38
However, this is the behaviour that currently not supported by
PostgreSQL
as stated below.https://www.postgresql.org/docs/current/static/transaction-iso.html#XACT-READ-COMMITTED
I would suggest to disable
IsTransactional
forUnitOfWork
if you are usingPostgreSQL
.Replying to myself, I just need to do that in
TokenAuthController.cs
: