This error keeps happening. Sometimes several times per day.
So far so good. I need a couple of weeks of dev to make sure it doesn't happen again.
before change:
"scripts": {
"ng": "ng",
"publish": "gulp build && ng build --prod",
"start": "gulp buildDev && ng serve --host 0.0.0.0 --port 4200",
"hmr": "gulp buildDev && ng serve --host 0.0.0.0 --port 4200 --hmr",
"test": "gulp buildDev && ng test",
"pree2e": "webdriver-manager update --standalone false --gecko false",
"e2e": "gulp buildDev && protractor",
"create-dynamic-bundles": "gulp buildDev"
},
after change:
"scripts": {
"ng": "ng",
"publish": "gulp build && ng build --prod",
"start": "ng serve --host 0.0.0.0 --port 4200",
"hmr": "gulp buildDev && ng serve --host 0.0.0.0 --port 4200 --hmr",
"test": "gulp buildDev && ng test",
"pree2e": "webdriver-manager update --standalone false --gecko false",
"e2e": "gulp buildDev && protractor",
"create-dynamic-bundles": "gulp buildDev"
},
Thank you for the suggestion.
Do you mean system RAM? I have 16 Gigs installed on my dev machine.
Client Node.js is 1.5G at startup.
Dev Studio Diagnostic Tools reports 489M Process Memory at startup.
I'll take a snapshot of these memorys next occurrence of the fault.
Or should I be looking at something else?
I'll try an upgrade to ANZ 9.0 and see if that solves the problem. I'll get back to you in a couple of weeks.
Last upgrade: ANZ 8.0.0
Server: Web.Public\package.json(9): "abp-web-resources": "^3.3.0"
Client: package.json: "abp-ng2-module": "^5.0.0", "abp-web-resources": "^4.1.0",
I answer my own question.
Use AppConsts.remoteServiceBaseUrl
directly in .ts code.
That solution works! Thank you!
I had to make a few minor changes to get the code to build. Here is the complete solution for anyone who might want to do something similar.
.Core/TtmUserLoginAttempts.cs (perform Add-Migration, Update-Database)
using Abp.Authorization.Users;
namespace ngTTM.Authorization.Users
{
public class TtmUserLoginAttempt : UserLoginAttempt
{
public string ClientInfo { get; set; }
}
}
.EntityFrameworkCore/EntityFrameworkCore/ntTTMDbContext.cs
public virtual DbSet<TtmUserLoginAttempt> TtmUserLoginAttempts { get; set; }
.Web.Core/Models/TokenAuth/AuthenticateModel.cs
public string ClientInfo { get; set; }
.Web.Core/Controllers/TokenAuthController.cs
private async Task<AbpLoginResult<Tenant, User>> GetLoginResultAsync(string usernameOrEmailAddress,
string password,
string tenancyName,
string clientInfo)
{
var loginResult = await _logInManager.LoginAsync(clientInfo,
usernameOrEmailAddress,
password,tenancyName);
switch (loginResult.Result)
{
case AbpLoginResultType.Success:
return loginResult;
default:
throw _abpLoginResultTypeHelper
.CreateExceptionForFailedLoginAttempt(loginResult.Result,
usernameOrEmailAddress,
tenancyName);
}
}
.Application/Authorization/LogInManager.cs
using Abp.Authorization;
using Abp.Authorization.Users;
using Abp.Configuration;
using Abp.Configuration.Startup;
using Abp.Dependency;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.Zero.Configuration;
using Microsoft.AspNetCore.Identity;
using ngTTM.Authorization.Roles;
using ngTTM.Authorization.Users;
using ngTTM.MultiTenancy;
using System.Threading.Tasks;
using System.Transactions;
namespace ngTTM.Authorization
{
public class LogInManager : AbpLogInManager<Tenant, Role, User>
{
private IRepository<TtmUserLoginAttempt, long> _ttmUserLoginAttemptRepository;
public LogInManager(
UserManager userManager,
IMultiTenancyConfig multiTenancyConfig,
IRepository<Tenant> tenantRepository,
IUnitOfWorkManager unitOfWorkManager,
ISettingManager settingManager,
IRepository<UserLoginAttempt, long> userLoginAttemptRepository,
IUserManagementConfig userManagementConfig,
IIocResolver iocResolver,
RoleManager roleManager,
IPasswordHasher<User> passwordHasher,
UserClaimsPrincipalFactory claimsPrincipalFactory,
IRepository<TtmUserLoginAttempt, long> ttmUserLoginAttemptRepository)
: base(
userManager,
multiTenancyConfig,
tenantRepository,
unitOfWorkManager,
settingManager,
userLoginAttemptRepository,
userManagementConfig,
iocResolver,
passwordHasher,
roleManager,
claimsPrincipalFactory)
{
_ttmUserLoginAttemptRepository = ttmUserLoginAttemptRepository;
}
[UnitOfWork]
public virtual async Task<AbpLoginResult<Tenant, User>> LoginAsync(string clientInfo,
string userNameOrEmailAddress,
string plainPassword,
string tenancyName = null,
bool shouldLockout = true)
{
var result = await LoginAsyncInternal(userNameOrEmailAddress, plainPassword, tenancyName, shouldLockout);
await SaveLoginAttemptAsync(clientInfo, result, tenancyName, userNameOrEmailAddress);
return result;
}
protected virtual async Task SaveLoginAttemptAsync(string clientInfo,
AbpLoginResult<Tenant, User> loginResult,
string tenancyName,
string userNameOrEmailAddress)
{
using (var uow = UnitOfWorkManager.Begin(TransactionScopeOption.Suppress))
{
var tenantId = loginResult.Tenant != null ? loginResult.Tenant.Id : (int?)null;
using (UnitOfWorkManager.Current.SetTenantId(tenantId))
{
var loginAttempt = new TtmUserLoginAttempt
{
TenantId = tenantId,
TenancyName = tenancyName,
UserId = loginResult.User != null ? loginResult.User.Id : (long?)null,
UserNameOrEmailAddress = userNameOrEmailAddress,
Result = loginResult.Result,
BrowserInfo = ClientInfoProvider.BrowserInfo,
ClientIpAddress = ClientInfoProvider.ClientIpAddress,
ClientName = ClientInfoProvider.ComputerName,
ClientInfo = clientInfo
};
await _ttmUserLoginAttemptRepository.InsertAsync(loginAttempt);
await UnitOfWorkManager.Current.SaveChangesAsync();
await uow.CompleteAsync();
}
}
}
}
}
/src/account/login/login.service.ts
authenticate(finallyCallback?: () => void, redirectUrl?: string, captchaResponse?: string): void {
finallyCallback = finallyCallback || (() => {
this.spinnerService.hide();
});
// We may switch to localStorage instead of cookies
this.authenticateModel.twoFactorRememberClientToken = this._utilsService.getCookieValue(LoginService.twoFactorRememberClientTokenName);
this.authenticateModel.singleSignIn = UrlHelper.getSingleSignIn();
this.authenticateModel.returnUrl = UrlHelper.getReturnUrl();
this.authenticateModel.captchaResponse = captchaResponse;
this.authenticateModel.clientInfo = this.getClientInfo();
this._tokenAuthService
.authenticate(this.authenticateModel)
.subscribe({
next: (result: AuthenticateResultModel) => {
this.processAuthenticateResult(result, redirectUrl);
finallyCallback();
},
error: (err: any) => {
finallyCallback();
}
});
}
I was not able to find a LoginAsync
method to override so used the closest match LoginAsyncInternal
.
This is what I have so far:
LoginManager.cs
using Abp.Authorization;
using Abp.Authorization.Users;
using Abp.Configuration;
using Abp.Configuration.Startup;
using Abp.Dependency;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.Zero.Configuration;
using Microsoft.AspNetCore.Identity;
using ngTTM.Authorization.Roles;
using ngTTM.Authorization.Users;
using ngTTM.MultiTenancy;
using System.Threading.Tasks;
using System.Transactions;
namespace ngTTM.Authorization
{
public class LogInManager : AbpLogInManager<Tenant, Role, User>
{
private IRepository<TtmUserLoginAttempt, long> _ttmUserLoginAttemptRepository;
private string _clientInfo;
public LogInManager(
UserManager userManager,
IMultiTenancyConfig multiTenancyConfig,
IRepository<Tenant> tenantRepository,
IUnitOfWorkManager unitOfWorkManager,
ISettingManager settingManager,
IRepository<UserLoginAttempt, long> userLoginAttemptRepository,
IUserManagementConfig userManagementConfig,
IIocResolver iocResolver,
RoleManager roleManager,
IPasswordHasher<User> passwordHasher,
UserClaimsPrincipalFactory claimsPrincipalFactory,
IRepository<TtmUserLoginAttempt, long> ttmUserLoginAttemptRepository)
: base(
userManager,
multiTenancyConfig,
tenantRepository,
unitOfWorkManager,
settingManager,
userLoginAttemptRepository,
userManagementConfig,
iocResolver,
passwordHasher,
roleManager,
claimsPrincipalFactory)
{
_ttmUserLoginAttemptRepository = ttmUserLoginAttemptRepository;
}
protected override Task<AbpLoginResult<Tenant, User>> LoginAsyncInternal(UserLoginInfo login, string tenancyName)
{
TtmUserLoginInfo ttmUserLoginInfo = login as TtmUserLoginInfo;
_clientInfo = ttmUserLoginInfo.ClientInfo;
return base.LoginAsyncInternal(login, tenancyName);
}
protected override async Task SaveLoginAttemptAsync(AbpLoginResult<Tenant, User> loginResult, string tenancyName, string userNameOrEmailAddress)
{
using (var uow = UnitOfWorkManager.Begin(TransactionScopeOption.Suppress))
{
var tenantId = loginResult.Tenant != null ? loginResult.Tenant.Id : (int?)null;
using (UnitOfWorkManager.Current.SetTenantId(tenantId))
{
var loginAttempt = new TtmUserLoginAttempt
{
TenantId = tenantId,
TenancyName = tenancyName,
UserId = loginResult.User != null ? loginResult.User.Id : (long?)null,
UserNameOrEmailAddress = userNameOrEmailAddress,
Result = loginResult.Result,
BrowserInfo = ClientInfoProvider.BrowserInfo,
ClientIpAddress = ClientInfoProvider.ClientIpAddress,
ClientName = ClientInfoProvider.ComputerName,
ClientInfo = _clientInfo
};
await _ttmUserLoginAttemptRepository.InsertAsync(loginAttempt);
await UnitOfWorkManager.Current.SaveChangesAsync();
await uow.CompleteAsync();
}
}
}
}
}
TtmUserLoginInfo.cs
using Microsoft.AspNetCore.Identity;
namespace ngTTM.Authorization.Users
{
public class TtmUserLoginInfo : UserLoginInfo
{
public string ClientInfo { get; set; }
public TtmUserLoginInfo(string loginProvider, string providerKey, string displayName, string clientInfo): base(loginProvider, providerKey, displayName)
{
ClientInfo = clientInfo;
}
}
}
TokenAuthController.cs
private async Task<AbpLoginResult<Tenant, User>> GetLoginResultAsync(string usernameOrEmailAddress, string password, string tenancyName, string clientInfo)
{
// the old way which works without clientInfo
//AbpLoginResult<Tenant, User> loginResult = await _logInManager.LoginAsync(usernameOrEmailAddress, password, tenancyName);
// the new way as recommended by @aaron
TtmUserLoginInfo ttmUserLoginInfo = new TtmUserLoginInfo("", "", "", clientInfo);
AbpLoginResult<Tenant, User> loginResult = await _logInManager.LoginAsync(ttmUserLoginInfo, tenancyName);
switch (loginResult.Result)
{
case AbpLoginResultType.Success:
return loginResult;
default:
throw _abpLoginResultTypeHelper.CreateExceptionForFailedLoginAttempt(loginResult.Result, usernameOrEmailAddress, tenancyName);
}
}
While I am able to pass clientInfo into LogInManager, the login fails (no surprise) since I don't know what values to use for loginProvider, providerKey, and displayName for UserLoginInfo.
What are the argument values to use to login to my site (and localhost)?
@ismcagdas -
Adding my ClientInfo string to the loginResult.Identity
claim list is too late in the process, as
LogInManager.SaveLoginAttemptAsync
is called before logInManager.LoginAsync
returns loginResult
.