From 21bcdcc92ce26e2d563bda84a5f3c6fb6fd77725 Mon Sep 17 00:00:00 2001 From: Eric Nguyen Date: Mon, 1 Jan 2024 11:16:21 +0700 Subject: [PATCH] fix mixdb permission --- .../MixDatabaseConfiguration.cs | 22 ++++++++-- .../mix.database/Entities/Cms/MixDatabase.cs | 11 ++--- .../Attributes/MixAuthorizeAttribute.cs | 2 +- .../MixAuthorizeOptionalAttribute.cs | 2 +- .../MixDatabaseAuthorizeAttribute.cs | 42 ++++++++++++------- .../mix.library/Startup/MixCommonService.cs | 2 - .../Services/MixPermissionService.cs | 34 +++++++++------ 7 files changed, 75 insertions(+), 40 deletions(-) diff --git a/src/platform/mix.database/Entities/Cms/EntityConfigurations/MixDatabaseConfiguration.cs b/src/platform/mix.database/Entities/Cms/EntityConfigurations/MixDatabaseConfiguration.cs index cd76a4428..c089c828d 100644 --- a/src/platform/mix.database/Entities/Cms/EntityConfigurations/MixDatabaseConfiguration.cs +++ b/src/platform/mix.database/Entities/Cms/EntityConfigurations/MixDatabaseConfiguration.cs @@ -1,6 +1,8 @@ using Microsoft.EntityFrameworkCore.Storage.ValueConversion; using Mix.Database.EntityConfigurations.Base; using Mix.Database.Services; +using Newtonsoft.Json.Linq; +using System.Collections.Generic; namespace Mix.Database.Entities.Cms.EntityConfigurations { @@ -44,22 +46,34 @@ public override void Configure(EntityTypeBuilder builder) builder.Property(e => e.ReadPermissions) .IsRequired(false) .HasColumnType($"{Config.NString}{Config.MediumLength}") - .HasCharSet(Config.CharSet); + .HasCharSet(Config.CharSet) + .HasConversion( + v => JArray.FromObject(v).ToString(Newtonsoft.Json.Formatting.None), + v => JArray.Parse(v ?? "[]").ToObject>()); builder.Property(e => e.CreatePermissions) .IsRequired(false) .HasColumnType($"{Config.NString}{Config.MediumLength}") - .HasCharSet(Config.CharSet); + .HasCharSet(Config.CharSet) + .HasConversion( + v => JArray.FromObject(v).ToString(Newtonsoft.Json.Formatting.None), + v => JArray.Parse(v ?? "[]").ToObject>()); builder.Property(e => e.UpdatePermissions) .IsRequired(false) .HasColumnType($"{Config.NString}{Config.MediumLength}") - .HasCharSet(Config.CharSet); + .HasCharSet(Config.CharSet) + .HasConversion( + v => JArray.FromObject(v).ToString(Newtonsoft.Json.Formatting.None), + v => JArray.Parse(v ?? "[]").ToObject>()); builder.Property(e => e.DeletePermissions) .IsRequired(false) .HasColumnType($"{Config.NString}{Config.MediumLength}") - .HasCharSet(Config.CharSet); + .HasCharSet(Config.CharSet) + .HasConversion( + v => JArray.FromObject(v).ToString(Newtonsoft.Json.Formatting.None), + v => JArray.Parse(v ?? "[]").ToObject>()); } } } diff --git a/src/platform/mix.database/Entities/Cms/MixDatabase.cs b/src/platform/mix.database/Entities/Cms/MixDatabase.cs index 5d0ed0d0a..1e160f6e1 100644 --- a/src/platform/mix.database/Entities/Cms/MixDatabase.cs +++ b/src/platform/mix.database/Entities/Cms/MixDatabase.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using Newtonsoft.Json.Linq; +using System.Collections.Generic; using System.ComponentModel.DataAnnotations.Schema; namespace Mix.Database.Entities.Cms @@ -10,10 +11,10 @@ public class MixDatabase : EntityBase public string DisplayName { get; set; } public virtual string Description { get; set; } public MixDatabaseType Type { get; set; } - public string ReadPermissions { get; set; } - public string CreatePermissions { get; set; } - public string UpdatePermissions { get; set; } - public string DeletePermissions { get; set; } + public List ReadPermissions { get; set; } + public List CreatePermissions { get; set; } + public List UpdatePermissions { get; set; } + public List DeletePermissions { get; set; } public bool SelfManaged { get; set; } public virtual ICollection MixDatabaseColumns { get; set; } diff --git a/src/platform/mix.library/Attributes/MixAuthorizeAttribute.cs b/src/platform/mix.library/Attributes/MixAuthorizeAttribute.cs index 04ac16cf7..89b1769cc 100644 --- a/src/platform/mix.library/Attributes/MixAuthorizeAttribute.cs +++ b/src/platform/mix.library/Attributes/MixAuthorizeAttribute.cs @@ -61,7 +61,7 @@ public void OnAuthorization(AuthorizationFilterContext context) private bool ValidEnpointPermission(AuthorizationFilterContext context) { - return _permissionService.CheckEndpointPermission(UserRoles, context.HttpContext.Request.Path, context.HttpContext.Request.Method); + return _permissionService.CheckEndpointPermissionAsync(UserRoles, context.HttpContext.Request.Path, context.HttpContext.Request.Method).Result; } private bool ValidToken() diff --git a/src/platform/mix.library/Attributes/MixAuthorizeOptionalAttribute.cs b/src/platform/mix.library/Attributes/MixAuthorizeOptionalAttribute.cs index 747b4c39c..5161c6f15 100644 --- a/src/platform/mix.library/Attributes/MixAuthorizeOptionalAttribute.cs +++ b/src/platform/mix.library/Attributes/MixAuthorizeOptionalAttribute.cs @@ -46,7 +46,7 @@ public void OnAuthorization(AuthorizationFilterContext context) private bool ValidEnpointPermission(AuthorizationFilterContext context) { - return _permissionService.CheckEndpointPermission(UserRoles, context.HttpContext.Request.Path, context.HttpContext.Request.Method); + return _permissionService.CheckEndpointPermissionAsync(UserRoles, context.HttpContext.Request.Path, context.HttpContext.Request.Method).Result; } private bool ValidToken() diff --git a/src/platform/mix.library/Attributes/MixDatabaseAuthorizeAttribute.cs b/src/platform/mix.library/Attributes/MixDatabaseAuthorizeAttribute.cs index e21d5ab99..728aeea07 100644 --- a/src/platform/mix.library/Attributes/MixDatabaseAuthorizeAttribute.cs +++ b/src/platform/mix.library/Attributes/MixDatabaseAuthorizeAttribute.cs @@ -53,7 +53,7 @@ public void OnAuthorization(AuthorizationFilterContext context) { if (ValidToken()) { - if (!IsInRoles(context.HttpContext.Request.Method, database)) + if (!IsInRoles(context.HttpContext.Request.Method, database, context.HttpContext.Request.Path)) { if (!ValidEnpointPermission(context)) { @@ -72,20 +72,27 @@ public void OnAuthorization(AuthorizationFilterContext context) private bool CheckByPassAuthenticate(string method, string path, MixDatabase database) { - return - (method == "GET" && (string.IsNullOrEmpty(database.ReadPermissions) || JArray.Parse(database.ReadPermissions).Count == 0)) - || (method == "POST" && path.EndsWith("filter") && (string.IsNullOrEmpty(database.ReadPermissions) || JArray.Parse(database.ReadPermissions).Count == 0)) - || (method == "POST" && (string.IsNullOrEmpty(database.CreatePermissions) || JArray.Parse(database.CreatePermissions).Count == 0)) - || ((method == "PUT" || method == "PATCH") && (string.IsNullOrEmpty(database.UpdatePermissions) || JArray.Parse(database.UpdatePermissions).Count == 0)) - || (method == "DELETE" && (string.IsNullOrEmpty(database.DeletePermissions) || JArray.Parse(database.DeletePermissions).Count == 0)); + return method switch { + "GET" => database.ReadPermissions == null + || database.ReadPermissions.Count == 0, + "POST" => (path.EndsWith("filter") && (database.ReadPermissions == null || database.ReadPermissions.Count == 0)) + || (!path.EndsWith("filter") && (database.CreatePermissions == null || database.CreatePermissions.Count == 0)), + "PUT" => database.UpdatePermissions == null + || database.UpdatePermissions.Count == 0, + "PATCH" => database.UpdatePermissions == null + || database.UpdatePermissions.Count == 0, + "DELETE" => database.DeletePermissions == null + || database.DeletePermissions.Count == 0, + _ => false + }; } #region Privates private bool ValidEnpointPermission(AuthorizationFilterContext context) { - return _permissionService.CheckEndpointPermission( - UserRoles, context.HttpContext.Request.Path, context.HttpContext.Request.Method); + return _permissionService.CheckEndpointPermissionAsync( + UserRoles, context.HttpContext.Request.Path, context.HttpContext.Request.Method).Result; } private bool ValidToken() @@ -95,7 +102,7 @@ private bool ValidToken() && DateTime.UtcNow < expireAt; } - private bool IsInRoles(string method, MixDatabase database) + private bool IsInRoles(string method, MixDatabase database, string path) { UserRoles = _idService.GetClaim(userPrinciple, MixClaims.Role).Split(',', StringSplitOptions.RemoveEmptyEntries) @@ -109,7 +116,15 @@ private bool IsInRoles(string method, MixDatabase database) switch (method) { case "GET": return CheckUserInRoles(database.ReadPermissions, UserRoles); - case "POST": return CheckUserInRoles(database.CreatePermissions, UserRoles); + case "POST": + if (path.EndsWith("filter")) + { + return CheckUserInRoles(database.ReadPermissions, UserRoles); + } + else + { + return CheckUserInRoles(database.CreatePermissions, UserRoles); + } case "PATCH": case "PUT": return CheckUserInRoles(database.UpdatePermissions, UserRoles); case "DELETE": return CheckUserInRoles(database.DeletePermissions, UserRoles); @@ -118,10 +133,9 @@ private bool IsInRoles(string method, MixDatabase database) } } - private bool CheckUserInRoles(string roles, string[] userRoles) + private bool CheckUserInRoles(List allowedRoles, string[] userRoles) { - var allowedRoles = JArray.Parse(roles).Values().ToArray(); - return allowedRoles.Length == 0 || allowedRoles.Any(r => userRoles.Any(ur => ur == $"{r}-{_idService.CurrentTenant.Id}")); + return allowedRoles == null || allowedRoles.Count == 0 || allowedRoles.Any(r => userRoles.Any(ur => ur == $"{r}-{_idService.CurrentTenant.Id}")); } #endregion diff --git a/src/platform/mix.library/Startup/MixCommonService.cs b/src/platform/mix.library/Startup/MixCommonService.cs index 7ab3b1798..cbd03e4f2 100644 --- a/src/platform/mix.library/Startup/MixCommonService.cs +++ b/src/platform/mix.library/Startup/MixCommonService.cs @@ -35,8 +35,6 @@ private static IServiceCollection AddMixCommonServices(this IServiceCollection s services.TryAddScoped(); services.TryAddScoped(); - MixPermissionService permissionSrv = services.GetService(); - permissionSrv.Reload().GetAwaiter().GetResult(); return services; } } diff --git a/src/platform/mix.service/Services/MixPermissionService.cs b/src/platform/mix.service/Services/MixPermissionService.cs index f33bfc889..4e4bf8ea0 100644 --- a/src/platform/mix.service/Services/MixPermissionService.cs +++ b/src/platform/mix.service/Services/MixPermissionService.cs @@ -1,5 +1,6 @@ using Microsoft.AspNetCore.Http; using Microsoft.EntityFrameworkCore; +using Microsoft.Extensions.DependencyInjection; using Mix.Constant.Constants; using Mix.Database.Entities.Account; using Mix.Database.Entities.Cms; @@ -16,17 +17,18 @@ namespace Mix.Service.Services { public sealed class MixPermissionService { - private readonly DatabaseService _databaseService; private readonly IHttpContextAccessor _httpContextAccessor; public Dictionary RoleEndpoints { get; private set; } private MixCmsAccountContext accountDbContext; private UnitOfWorkInfo uow; private int? _tenantId; + private IServiceScope _serviceScope { get; set; } + private readonly IServiceProvider _servicesProvider; public MixPermissionService( - IHttpContextAccessor httpContextAccessor) - { + IHttpContextAccessor httpContextAccessor, IServiceProvider servicesProvider) + { + _servicesProvider = servicesProvider; _httpContextAccessor = httpContextAccessor; - _databaseService = new(httpContextAccessor); _tenantId = _httpContextAccessor.HttpContext?.Session.GetInt32(MixRequestQueryKeywords.TenantId) ?? 1; } @@ -36,10 +38,10 @@ public async Task Reload() { try { - uow = new(new MixDbDbContext(_databaseService)); + uow = GetRequiredService>(); RoleEndpoints = new Dictionary(); - accountDbContext = new MixCmsAccountContext(_databaseService); - using var cmsDbContext = new MixCmsContext(_databaseService); + accountDbContext = GetRequiredService(); + var cmsDbContext = GetRequiredService(); var roles = await accountDbContext.MixRoles.ToListAsync(); @@ -85,16 +87,22 @@ public async Task Reload() { throw new MixException(Heart.Enums.MixErrorStatus.Badrequest, ex); } - finally - { - uow.Dispose(); - accountDbContext.Dispose(); - } } } - public bool CheckEndpointPermission(string[] userRoles, PathString path, string method) + private T GetRequiredService() + where T : class + { + _serviceScope ??= _servicesProvider.CreateScope(); + return _serviceScope.ServiceProvider.GetRequiredService(); + } + + public async Task CheckEndpointPermissionAsync(string[] userRoles, PathString path, string method) { + if(RoleEndpoints == null) + { + await Reload(); + } if (userRoles == null) { return false;