ConcurrentUserLimit tanımlamalası
This commit is contained in:
parent
c4671f7051
commit
70fb9ae499
17 changed files with 126 additions and 11 deletions
|
|
@ -10,6 +10,7 @@ public class CreateUpdateUserInput
|
||||||
public string Email { get; set; }
|
public string Email { get; set; }
|
||||||
public string PhoneNumber { get; set; }
|
public string PhoneNumber { get; set; }
|
||||||
public string Password { get; set; }
|
public string Password { get; set; }
|
||||||
|
public string WorkHour { get; set; }
|
||||||
public bool? IsActive { get; set; }
|
public bool? IsActive { get; set; }
|
||||||
public bool? LockoutEnabled { get; set; }
|
public bool? LockoutEnabled { get; set; }
|
||||||
public string[] RoleNames { get; set; }
|
public string[] RoleNames { get; set; }
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,10 @@ public static class PlatformSignInResultExtensions
|
||||||
{
|
{
|
||||||
return PlatformConsts.UserCannotSignInErrors.LoginNotAllowed_WorkHour;
|
return PlatformConsts.UserCannotSignInErrors.LoginNotAllowed_WorkHour;
|
||||||
}
|
}
|
||||||
|
if (resultP.IsNotAllowed_ConcurrentUserLimit)
|
||||||
|
{
|
||||||
|
return PlatformConsts.UserCannotSignInErrors.LoginNotAllowed_ConcurrentUserLimit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/// Added -->
|
/// Added -->
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,6 +7,7 @@ using Volo.Abp;
|
||||||
using Volo.Abp.Domain.Entities;
|
using Volo.Abp.Domain.Entities;
|
||||||
using Volo.Abp.Identity;
|
using Volo.Abp.Identity;
|
||||||
using Volo.Abp.TenantManagement;
|
using Volo.Abp.TenantManagement;
|
||||||
|
using Volo.Abp.Data;
|
||||||
|
|
||||||
namespace Sozsoft.Platform.ListForms.DynamicApi;
|
namespace Sozsoft.Platform.ListForms.DynamicApi;
|
||||||
|
|
||||||
|
|
@ -33,7 +34,7 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
|
||||||
[Authorize(IdentityPermissions.Users.Create)]
|
[Authorize(IdentityPermissions.Users.Create)]
|
||||||
public async Task PostUserInsertAsync(DynamicApiBaseInput<CreateUpdateUserInput> input)
|
public async Task PostUserInsertAsync(DynamicApiBaseInput<CreateUpdateUserInput> input)
|
||||||
{
|
{
|
||||||
await identityUserAppService.CreateAsync(new IdentityUserCreateDto
|
var user = new IdentityUserCreateDto
|
||||||
{
|
{
|
||||||
UserName = input.Data.Email,
|
UserName = input.Data.Email,
|
||||||
Name = input.Data.Name,
|
Name = input.Data.Name,
|
||||||
|
|
@ -43,8 +44,11 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
|
||||||
IsActive = input.Data.IsActive ?? true,
|
IsActive = input.Data.IsActive ?? true,
|
||||||
LockoutEnabled = true,
|
LockoutEnabled = true,
|
||||||
Password = input.Data.Password,
|
Password = input.Data.Password,
|
||||||
RoleNames = [] //input.Data.RoleNames,
|
RoleNames = [], //input.Data.RoleNames,
|
||||||
});
|
};
|
||||||
|
user.SetProperty(PlatformConsts.AbpIdentity.User.WorkHour, input.Data.WorkHour);
|
||||||
|
|
||||||
|
await identityUserAppService.CreateAsync(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Authorize(IdentityPermissions.Users.Update)]
|
[Authorize(IdentityPermissions.Users.Update)]
|
||||||
|
|
@ -54,7 +58,7 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
|
||||||
{
|
{
|
||||||
throw new UserFriendlyException(L["RecordNotFound"]);
|
throw new UserFriendlyException(L["RecordNotFound"]);
|
||||||
}
|
}
|
||||||
var id = Guid.Parse(input.Keys[0].ToString());
|
var id = Guid.Parse(input.Keys[0]!.ToString()!);
|
||||||
var entity = await identityUserAppService.GetAsync(id) ?? throw new EntityNotFoundException(L["RecordNotFound"]);
|
var entity = await identityUserAppService.GetAsync(id) ?? throw new EntityNotFoundException(L["RecordNotFound"]);
|
||||||
var user = new IdentityUserUpdateDto
|
var user = new IdentityUserUpdateDto
|
||||||
{
|
{
|
||||||
|
|
@ -71,6 +75,10 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
|
||||||
{
|
{
|
||||||
user.Password = input.Data.Password;
|
user.Password = input.Data.Password;
|
||||||
}
|
}
|
||||||
|
if (input.Data.WorkHour != null)
|
||||||
|
{
|
||||||
|
user.SetProperty(PlatformConsts.AbpIdentity.User.WorkHour, input.Data.WorkHour);
|
||||||
|
}
|
||||||
|
|
||||||
await identityUserAppService.UpdateAsync(id, user);
|
await identityUserAppService.UpdateAsync(id, user);
|
||||||
}
|
}
|
||||||
|
|
@ -94,7 +102,7 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
|
||||||
{
|
{
|
||||||
throw new UserFriendlyException(L["RecordNotFound"]);
|
throw new UserFriendlyException(L["RecordNotFound"]);
|
||||||
}
|
}
|
||||||
var id = Guid.Parse(input.Keys[0].ToString());
|
var id = Guid.Parse(input.Keys[0]!.ToString()!);
|
||||||
var entity = await identityRoleAppService.GetAsync(id) ?? throw new EntityNotFoundException(L["RecordNotFound"]);
|
var entity = await identityRoleAppService.GetAsync(id) ?? throw new EntityNotFoundException(L["RecordNotFound"]);
|
||||||
var role = new IdentityRoleUpdateDto
|
var role = new IdentityRoleUpdateDto
|
||||||
{
|
{
|
||||||
|
|
@ -142,7 +150,7 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
|
||||||
throw new UserFriendlyException(L["RecordNotFound"]);
|
throw new UserFriendlyException(L["RecordNotFound"]);
|
||||||
}
|
}
|
||||||
|
|
||||||
var id = Guid.Parse(input.Keys[0].ToString());
|
var id = Guid.Parse(input.Keys[0]!.ToString()!);
|
||||||
var entity = await tenantRepository.GetAsync(id)
|
var entity = await tenantRepository.GetAsync(id)
|
||||||
?? throw new EntityNotFoundException(L["RecordNotFound"]);
|
?? throw new EntityNotFoundException(L["RecordNotFound"]);
|
||||||
|
|
||||||
|
|
@ -176,7 +184,7 @@ public class ListFormDynamicApiAppService : PlatformAppService, IListFormDynamic
|
||||||
{
|
{
|
||||||
throw new UserFriendlyException(L["RecordNotFound"]);
|
throw new UserFriendlyException(L["RecordNotFound"]);
|
||||||
}
|
}
|
||||||
var id = Guid.Parse(input.Keys[0].ToString());
|
var id = Guid.Parse(input.Keys[0]!.ToString()!);
|
||||||
await tenantRepository.DeleteAsync(id);
|
await tenantRepository.DeleteAsync(id);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
{
|
{
|
||||||
"Languages": [
|
"Languages": [
|
||||||
{
|
{
|
||||||
"cultureName": "ar",
|
"cultureName": "ar",
|
||||||
|
|
@ -3113,6 +3113,12 @@
|
||||||
"key": "Abp.Identity.LoginNotAllowed_WorkHour",
|
"key": "Abp.Identity.LoginNotAllowed_WorkHour",
|
||||||
"en": "You cannot sign in outside of the allowed work hours.",
|
"en": "You cannot sign in outside of the allowed work hours.",
|
||||||
"tr": "İzin verilen iş saatleri dışında giriş yapamazsınız."
|
"tr": "İzin verilen iş saatleri dışında giriş yapamazsınız."
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"resourceName": "Platform",
|
||||||
|
"key": "Abp.Identity.ConcurrentUserLimitError",
|
||||||
|
"en": "The maximum number of simultaneous users has been reached. Please try again later.",
|
||||||
|
"tr": "Eş zamanlı kullanıcı limiti dolmuştur. Lütfen daha sonra tekrar deneyiniz."
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"resourceName": "Platform",
|
"resourceName": "Platform",
|
||||||
|
|
|
||||||
|
|
@ -68,6 +68,7 @@ public static class PlatformConsts
|
||||||
public const string Email = "Email";
|
public const string Email = "Email";
|
||||||
public const string Website = "Website";
|
public const string Website = "Website";
|
||||||
public const string MenuGroup = "MenuGroup";
|
public const string MenuGroup = "MenuGroup";
|
||||||
|
public const string MaxConcurrentUsers = "MaxConcurrentUsers";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class AbpIdentity
|
public static class AbpIdentity
|
||||||
|
|
@ -107,6 +108,7 @@ public static class PlatformConsts
|
||||||
public const string LoginEndDateError = GroupName + ".LoginEndDateError";
|
public const string LoginEndDateError = GroupName + ".LoginEndDateError";
|
||||||
public const string TenantIsPassive = GroupName + ".TenantIsPassive";
|
public const string TenantIsPassive = GroupName + ".TenantIsPassive";
|
||||||
public const string LoginNotAllowed_WorkHour = GroupName + ".LoginNotAllowed_WorkHour";
|
public const string LoginNotAllowed_WorkHour = GroupName + ".LoginNotAllowed_WorkHour";
|
||||||
|
public const string ConcurrentUserLimitError = GroupName + ".ConcurrentUserLimitError";
|
||||||
public const string CaptchaWrongCode = GroupName + ".CaptchaWrongCode";
|
public const string CaptchaWrongCode = GroupName + ".CaptchaWrongCode";
|
||||||
public const string TwoFactorWrongCode = GroupName + ".TwoFactorWrongCode";
|
public const string TwoFactorWrongCode = GroupName + ".TwoFactorWrongCode";
|
||||||
public const string SignOut = GroupName + ".SignOut";
|
public const string SignOut = GroupName + ".SignOut";
|
||||||
|
|
@ -450,6 +452,7 @@ public static class PlatformConsts
|
||||||
public static string LoginNotAllowed_TenantIsPassive { get; set; } = "UserCannotSignInTenantIsPassive";
|
public static string LoginNotAllowed_TenantIsPassive { get; set; } = "UserCannotSignInTenantIsPassive";
|
||||||
public static string LoginNotAllowed_TenantNotFound { get; set; } = "UserCannotSignInTenantNotFound";
|
public static string LoginNotAllowed_TenantNotFound { get; set; } = "UserCannotSignInTenantNotFound";
|
||||||
public static string LoginNotAllowed_WorkHour { get; set; } = "UserCannotSignInWorkHour";
|
public static string LoginNotAllowed_WorkHour { get; set; } = "UserCannotSignInWorkHour";
|
||||||
|
public static string LoginNotAllowed_ConcurrentUserLimit { get; set; } = "UserCannotSignInConcurrentUserLimit";
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class GridOptions
|
public static class GridOptions
|
||||||
|
|
|
||||||
|
|
@ -93,6 +93,7 @@ public static class PlatformModuleExtensionConfigurator
|
||||||
tenantConfig.ConfigureTenant(entity =>
|
tenantConfig.ConfigureTenant(entity =>
|
||||||
{
|
{
|
||||||
entity.AddOrUpdateProperty<bool>("IsActive");
|
entity.AddOrUpdateProperty<bool>("IsActive");
|
||||||
|
entity.AddOrUpdateProperty<int?>("MaxConcurrentUsers");
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -165,5 +165,14 @@ public static class AbpTenantExtensions
|
||||||
{
|
{
|
||||||
return tenant.GetProperty<string>(PlatformConsts.Tenants.MenuGroup);
|
return tenant.GetProperty<string>(PlatformConsts.Tenants.MenuGroup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void SetMaxConcurrentUsers(this Tenant tenant, int? maxConcurrentUsers)
|
||||||
|
{
|
||||||
|
tenant.SetProperty(PlatformConsts.Tenants.MaxConcurrentUsers, maxConcurrentUsers.HasValue ? (object)maxConcurrentUsers.Value : null);
|
||||||
|
}
|
||||||
|
public static int? GetMaxConcurrentUsers(this Tenant tenant)
|
||||||
|
{
|
||||||
|
return tenant.GetProperty<int?>(PlatformConsts.Tenants.MaxConcurrentUsers);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -30,6 +30,8 @@ public class PlatformSignInResult : SignInResult
|
||||||
|
|
||||||
public bool IsNotAllowed_WorkHour { get; set; }
|
public bool IsNotAllowed_WorkHour { get; set; }
|
||||||
|
|
||||||
|
public bool IsNotAllowed_ConcurrentUserLimit { get; set; }
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
return
|
return
|
||||||
|
|
@ -40,6 +42,7 @@ public class PlatformSignInResult : SignInResult
|
||||||
ShouldChangePasswordPeriodic ? "ShouldChangePasswordPeriodic" :
|
ShouldChangePasswordPeriodic ? "ShouldChangePasswordPeriodic" :
|
||||||
IsNotAllowed_TenantIsPassive ? "NotAllowed_TenantIsPassive" :
|
IsNotAllowed_TenantIsPassive ? "NotAllowed_TenantIsPassive" :
|
||||||
IsNotAllowed_WorkHour ? "NotAllowed_WorkHour" :
|
IsNotAllowed_WorkHour ? "NotAllowed_WorkHour" :
|
||||||
|
IsNotAllowed_ConcurrentUserLimit ? "NotAllowed_ConcurrentUserLimit" :
|
||||||
base.ToString();
|
base.ToString();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -217,6 +217,15 @@ public static class PlatformEfCoreEntityExtensionMappings
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
ObjectExtensionManager.Instance
|
||||||
|
.MapEfCoreProperty<Tenant, int?>(
|
||||||
|
PlatformConsts.Tenants.MaxConcurrentUsers,
|
||||||
|
(entityBuilder, propertyBuilder) =>
|
||||||
|
{
|
||||||
|
propertyBuilder.HasDefaultValue(0);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
ObjectExtensionManager.Instance
|
ObjectExtensionManager.Instance
|
||||||
.MapEfCoreProperty<PermissionDefinitionRecord, string>(
|
.MapEfCoreProperty<PermissionDefinitionRecord, string>(
|
||||||
PlatformConsts.Permissions.MenuGroup,
|
PlatformConsts.Permissions.MenuGroup,
|
||||||
|
|
|
||||||
|
|
@ -13,7 +13,7 @@ using Volo.Abp.EntityFrameworkCore;
|
||||||
namespace Sozsoft.Platform.Migrations
|
namespace Sozsoft.Platform.Migrations
|
||||||
{
|
{
|
||||||
[DbContext(typeof(PlatformDbContext))]
|
[DbContext(typeof(PlatformDbContext))]
|
||||||
[Migration("20260426180109_Initial")]
|
[Migration("20260427070853_Initial")]
|
||||||
partial class Initial
|
partial class Initial
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|
@ -6164,6 +6164,11 @@ namespace Sozsoft.Platform.Migrations
|
||||||
.HasColumnType("uniqueidentifier")
|
.HasColumnType("uniqueidentifier")
|
||||||
.HasColumnName("LastModifierId");
|
.HasColumnName("LastModifierId");
|
||||||
|
|
||||||
|
b.Property<int?>("MaxConcurrentUsers")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int")
|
||||||
|
.HasDefaultValue(0);
|
||||||
|
|
||||||
b.Property<string>("MenuGroup")
|
b.Property<string>("MenuGroup")
|
||||||
.HasMaxLength(64)
|
.HasMaxLength(64)
|
||||||
.HasColumnType("nvarchar(64)");
|
.HasColumnType("nvarchar(64)");
|
||||||
|
|
@ -350,6 +350,7 @@ namespace Sozsoft.Platform.Migrations
|
||||||
FaxNumber = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true),
|
FaxNumber = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true),
|
||||||
Founder = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
Founder = table.Column<string>(type: "nvarchar(max)", nullable: true),
|
||||||
IsActive = table.Column<bool>(type: "bit", nullable: false, defaultValue: true),
|
IsActive = table.Column<bool>(type: "bit", nullable: false, defaultValue: true),
|
||||||
|
MaxConcurrentUsers = table.Column<int>(type: "int", nullable: true, defaultValue: 0),
|
||||||
MenuGroup = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true),
|
MenuGroup = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true),
|
||||||
MobileNumber = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true),
|
MobileNumber = table.Column<string>(type: "nvarchar(20)", maxLength: 20, nullable: true),
|
||||||
OrganizationName = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true),
|
OrganizationName = table.Column<string>(type: "nvarchar(64)", maxLength: 64, nullable: true),
|
||||||
|
|
@ -6161,6 +6161,11 @@ namespace Sozsoft.Platform.Migrations
|
||||||
.HasColumnType("uniqueidentifier")
|
.HasColumnType("uniqueidentifier")
|
||||||
.HasColumnName("LastModifierId");
|
.HasColumnName("LastModifierId");
|
||||||
|
|
||||||
|
b.Property<int?>("MaxConcurrentUsers")
|
||||||
|
.ValueGeneratedOnAdd()
|
||||||
|
.HasColumnType("int")
|
||||||
|
.HasDefaultValue(0);
|
||||||
|
|
||||||
b.Property<string>("MenuGroup")
|
b.Property<string>("MenuGroup")
|
||||||
.HasMaxLength(64)
|
.HasMaxLength(64)
|
||||||
.HasColumnType("nvarchar(64)");
|
.HasColumnType("nvarchar(64)");
|
||||||
|
|
|
||||||
|
|
@ -24,6 +24,9 @@ public static class PlatformEventIds
|
||||||
|
|
||||||
public static EventId UserCannotSignInWorkHour =
|
public static EventId UserCannotSignInWorkHour =
|
||||||
new(18, PlatformConsts.UserCannotSignInErrors.LoginNotAllowed_WorkHour);
|
new(18, PlatformConsts.UserCannotSignInErrors.LoginNotAllowed_WorkHour);
|
||||||
|
|
||||||
|
public static EventId UserCannotSignInConcurrentUserLimit =
|
||||||
|
new(19, PlatformConsts.UserCannotSignInErrors.LoginNotAllowed_ConcurrentUserLimit);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -64,6 +64,11 @@ public class PlatformLoginResult : AbpLoginResult
|
||||||
PResult = PlatformLoginResultType.NotAllowedWorkHour;
|
PResult = PlatformLoginResultType.NotAllowedWorkHour;
|
||||||
Description = L[PlatformConsts.AbpIdentity.User.LoginNotAllowed_WorkHour];
|
Description = L[PlatformConsts.AbpIdentity.User.LoginNotAllowed_WorkHour];
|
||||||
}
|
}
|
||||||
|
else if (resultP.IsNotAllowed_ConcurrentUserLimit)
|
||||||
|
{
|
||||||
|
PResult = PlatformLoginResultType.ConcurrentUserLimit;
|
||||||
|
Description = L[PlatformConsts.AbpIdentity.User.ConcurrentUserLimitError];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -15,6 +15,7 @@ public enum PlatformLoginResultType : byte
|
||||||
LoginEndDateDue,
|
LoginEndDateDue,
|
||||||
ShowCaptcha,
|
ShowCaptcha,
|
||||||
TenantIsPassive,
|
TenantIsPassive,
|
||||||
NotAllowedWorkHour
|
NotAllowedWorkHour,
|
||||||
|
ConcurrentUserLimit
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -18,6 +18,7 @@ using Volo.Abp.TenantManagement;
|
||||||
using Volo.Abp.Timing;
|
using Volo.Abp.Timing;
|
||||||
using IdentityUser = Volo.Abp.Identity.IdentityUser;
|
using IdentityUser = Volo.Abp.Identity.IdentityUser;
|
||||||
using SignInResult = Microsoft.AspNetCore.Identity.SignInResult;
|
using SignInResult = Microsoft.AspNetCore.Identity.SignInResult;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
namespace Sozsoft.Platform.Identity;
|
namespace Sozsoft.Platform.Identity;
|
||||||
|
|
||||||
|
|
@ -33,6 +34,7 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
|
||||||
private readonly IRepository<WorkHour, Guid> repositoryWorkHour;
|
private readonly IRepository<WorkHour, Guid> repositoryWorkHour;
|
||||||
private readonly ITenantRepository tenantRepository;
|
private readonly ITenantRepository tenantRepository;
|
||||||
private readonly IdentityUserManager userManager;
|
private readonly IdentityUserManager userManager;
|
||||||
|
private readonly IIdentitySessionRepository identitySessionRepository;
|
||||||
|
|
||||||
public PlatformSignInManager(
|
public PlatformSignInManager(
|
||||||
IdentityUserManager userManager,
|
IdentityUserManager userManager,
|
||||||
|
|
@ -47,7 +49,8 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
|
||||||
IClock clock,
|
IClock clock,
|
||||||
IRepository<IpRestriction, Guid> repositoryIp,
|
IRepository<IpRestriction, Guid> repositoryIp,
|
||||||
IRepository<WorkHour, Guid> repositoryWorkHour,
|
IRepository<WorkHour, Guid> repositoryWorkHour,
|
||||||
ITenantRepository tenantRepository
|
ITenantRepository tenantRepository,
|
||||||
|
IIdentitySessionRepository identitySessionRepository
|
||||||
) : base(
|
) : base(
|
||||||
userManager,
|
userManager,
|
||||||
contextAccessor,
|
contextAccessor,
|
||||||
|
|
@ -64,6 +67,7 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
|
||||||
this.repositoryWorkHour = repositoryWorkHour;
|
this.repositoryWorkHour = repositoryWorkHour;
|
||||||
this.tenantRepository = tenantRepository;
|
this.tenantRepository = tenantRepository;
|
||||||
this.userManager = userManager;
|
this.userManager = userManager;
|
||||||
|
this.identitySessionRepository = identitySessionRepository;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> PreSignInCheckAsync(IdentityUser user)
|
public async Task<bool> PreSignInCheckAsync(IdentityUser user)
|
||||||
|
|
@ -98,6 +102,10 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
|
||||||
{
|
{
|
||||||
return new PlatformSignInResult() { IsNotAllowed_WorkHour = true };
|
return new PlatformSignInResult() { IsNotAllowed_WorkHour = true };
|
||||||
}
|
}
|
||||||
|
if (!await CanSignInConcurrentLimitAsync(user))
|
||||||
|
{
|
||||||
|
return new PlatformSignInResult() { IsNotAllowed_ConcurrentUserLimit = true };
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -256,5 +264,47 @@ public class PlatformSignInManager : AbpSignInManager, IPlatformSignInManager
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Prevents login when the tenant's concurrent user limit is reached.
|
||||||
|
/// Counts distinct active users (by UserId) in AbpSessions for the tenant.
|
||||||
|
/// A user who already has an active session is not counted as a new concurrent user.
|
||||||
|
/// </summary>
|
||||||
|
private async Task<bool> CanSignInConcurrentLimitAsync(IdentityUser user)
|
||||||
|
{
|
||||||
|
if (!user.TenantId.HasValue)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var tenant = await tenantRepository.FindAsync(user.TenantId.Value);
|
||||||
|
if (tenant == null)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var maxConcurrentUsers = tenant.GetMaxConcurrentUsers();
|
||||||
|
if (!maxConcurrentUsers.HasValue || maxConcurrentUsers.Value <= 0)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
var sessions = await identitySessionRepository.GetListAsync();
|
||||||
|
var activeUserCount = sessions
|
||||||
|
.Where(s => s.UserId != user.Id)
|
||||||
|
.Select(s => s.UserId)
|
||||||
|
.Distinct()
|
||||||
|
.Count();
|
||||||
|
|
||||||
|
if (activeUserCount >= maxConcurrentUsers.Value)
|
||||||
|
{
|
||||||
|
Logger.LogWarning(PlatformEventIds.UserCannotSignInConcurrentUserLimit,
|
||||||
|
"Tenant {TenantId} concurrent user limit of {Limit} reached. Active users: {ActiveCount}.",
|
||||||
|
user.TenantId, maxConcurrentUsers.Value, activeUserCount);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ const PlatformLoginResultType = {
|
||||||
NotAllowedIp: 19, // IpRestriction tablosu, Mesaj: Identity:IpRestrictionError
|
NotAllowedIp: 19, // IpRestriction tablosu, Mesaj: Identity:IpRestrictionError
|
||||||
LoginEndDateDue: 20, // LoginEndDate:>Today, Buton: ShowExtendMyLoginButton, Mesaj: Identity:LoginEndDateError, >LoginEndDate
|
LoginEndDateDue: 20, // LoginEndDate:>Today, Buton: ShowExtendMyLoginButton, Mesaj: Identity:LoginEndDateError, >LoginEndDate
|
||||||
ShowCaptcha: 21, // AccessFailedCount>AccountCaptchaMaxFailedAccessAttempts, Sayfa: Show Captcha
|
ShowCaptcha: 21, // AccessFailedCount>AccountCaptchaMaxFailedAccessAttempts, Sayfa: Show Captcha
|
||||||
|
ConcurrentUserLimit: 22, // MaxConcurrentUsers limiti dolduğunda, Mesaj: Identity:ConcurrentUserLimitError
|
||||||
}
|
}
|
||||||
|
|
||||||
export default PlatformLoginResultType
|
export default PlatformLoginResultType
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue