Browse Source

follow example project

HOME 2 years ago
parent
commit
d791d56206
34 changed files with 272 additions and 369 deletions
  1. 1 1
      VCommon.Ioc.Tests/ChildrenContainerTest.cs
  2. 1 1
      VCommon.VApplication/Auditing/ApplicationServiceAuditInterceptorBase.cs
  3. 1 1
      VCommon.VApplication/Authorization/IOrgManager.cs
  4. 14 9
      VCommon.VApplication/Authorization/IPermissionManager.cs
  5. 6 5
      VCommon.VApplication/Authorization/PermissionNode.cs
  6. 2 6
      VCommon.VApplication/Authorization/PermissionNodeOutput.cs
  7. 22 12
      VCommon.VApplication/Authorization/PermissionTree.cs
  8. 9 0
      VCommon.VApplication/DataStore/IUserStore.cs
  9. 1 1
      VCommon.VApplication/Dto/IPassaveFilter.cs
  10. 14 0
      VCommon.VApplication/EntityFrameworkCore/VAppEfDataFilters.cs
  11. 54 8
      VCommon.VApplication/EntityFrameworkCore/VAppEfRepository.cs
  12. 2 0
      VCommon.VApplication/IVSession.cs
  13. 1 1
      VCommon.VApplication/Linq.Expressions/PredicateExpressionBuilderExtensionMethods.cs
  14. 17 0
      VCommon.VApplication/VEmptySession.cs
  15. 2 2
      VCommon.VAutoMapper/Internals/MiddleClass.cs
  16. 8 6
      VCommon.VAutoMapper/Internals/MiddleMapper.cs
  17. 9 2
      VCommon.VAutoMapper/VAutoMapper.cs
  18. 2 1
      VCommon.VEntity/IMustHaveOrg.cs
  19. 5 8
      VCommon.VEntity/VEntityBase.cs
  20. 0 39
      VCommon.VEntityFrameworkCore.Tests/Migrations/20210622032917_CreateDataBaseTest.Designer.cs
  21. 0 44
      VCommon.VEntityFrameworkCore.Tests/Migrations/20210626092232_AddFilterField.Designer.cs
  22. 0 24
      VCommon.VEntityFrameworkCore.Tests/Migrations/20210626092232_AddFilterField.cs
  23. 0 50
      VCommon.VEntityFrameworkCore.Tests/Migrations/20210626094351_AddAuditField.Designer.cs
  24. 0 35
      VCommon.VEntityFrameworkCore.Tests/Migrations/20210626094351_AddAuditField.cs
  25. 0 32
      VCommon.VEntityFrameworkCore.Tests/Migrations/20210627052532_ChangeKeyField.cs
  26. 4 5
      VCommon.VEntityFrameworkCore.Tests/Migrations/20210627052532_ChangeKeyField.Designer.cs
  27. 8 4
      VCommon.VEntityFrameworkCore.Tests/Migrations/20210622032917_CreateDataBaseTest.cs
  28. 2 3
      VCommon.VEntityFrameworkCore.Tests/Migrations/TestDbContextModelSnapshot.cs
  29. 1 10
      VCommon.VEntityFrameworkCore/VEfDataFilters.cs
  30. 5 6
      VCommon.VEntityFrameworkCore/VEfRepositoryBase.cs
  31. 41 36
      VCommon.VOpenApi.VAspNetCore/ApiMiddleware.cs
  32. 0 12
      VCommon.VOpenApi.VAspNetCore/IUserTokenStore.cs
  33. 22 5
      VCommon.VOpenApi.VAspNetCore/VSession.cs
  34. 18 0
      VCommon.VOpenApi.VAspNetCore/VFriendlyException.cs

+ 1 - 1
VCommon.Ioc.Tests/ChildrenContainerTest.cs

@@ -10,7 +10,7 @@ namespace VCommon.Ioc.Tests
             public int UserId { get; set; }
         }
 
-        public class Setting : IContainerInstanceIocClass
+        public class Setting : ISingletonIocClass
         {
             public string Value { get; set; } = "Keep";
         }

+ 1 - 1
VCommon.VApplication/Auditing/ApplicationServiceAuditInterceptorBase.cs

@@ -84,7 +84,7 @@ namespace VCommon.VApplication.Auditing
             var orgMgr = IocManager.Resolve<IOrgManager>();
             if (false == orgMgr.Enabled) return;
 
-            var uvOrg = orgMgr.GetUserVisionOrgs(Session.GetTenantId(), Session.GetUserId()).ToArray();
+            var uvOrg = orgMgr.GetUserVisionOrg(Session.GetTenantId(), Session.GetUserId()).ToArray();
             if (mustHaveOrg.All(argument => argument.OrgId.In(uvOrg))) return;
 
             var vrwFriendlyException = new VApplicationAuthException("拒绝访问:您没有权限操作此对象", AuthReason.AccessDenied);

+ 1 - 1
VCommon.VApplication/Authorization/IOrgManager.cs

@@ -7,6 +7,6 @@ namespace VCommon.VApplication.Authorization
     {
         bool Enabled { get; }
 
-        IReadOnlyCollection<Guid> GetUserVisionOrgs(Guid tenantId,Guid userId);
+        IReadOnlyCollection<Guid> GetUserVisionOrg(Guid? tenantId, Guid? userId);
     }
 }

+ 14 - 9
VCommon.VApplication/Authorization/IPermissionManager.cs

@@ -5,19 +5,24 @@ namespace VCommon.VApplication.Authorization
 {
     public interface IPermissionManager
     {
-        /// <summary> 检查权限代码是否合法 </summary>
-        bool ValidPermission(string permission);
+        ///// <summary> 检查权限代码是否合法 </summary>
+        //bool ValidPermission(string permission);
 
         /// <summary> 检查指定的用户是否有权限 </summary>
-        bool CheckPermission(Guid tenantId, Guid userId, params string[] hasAnyPermission);
+        bool CheckPermission(Guid? tenantId, Guid userId, params string[] hasAnyPermission);
 
-        /// <summary> 获取当前产品完整权限树 </summary>
-        IReadOnlyCollection<PermissionNode> GetAllPermissionTree();
+        ///// <summary> 获取当前用户权限代码集合 </summary>
+        //IReadOnlyCollection<string> GetUserPermissionCodes(Guid? tenantId, Guid userId);
 
-        /// <summary> 获取当前可用权限树 </summary>
-        IReadOnlyCollection<PermissionNodeOutput> GetPermissionTreeOutput();
+        ///// <summary> 获取平台端完整权限 </summary>
+        //IReadOnlyCollection<string> GetHostPermissionNode();
+
+        ///// <summary> 获取租户端完整权限</summary>
+        //IReadOnlyCollection<string> GetTenantPermissionNode(ICollection<string> licPermissions);
+
+
+        ///// <summary> 获取当前可用权限树 </summary>
+        //IReadOnlyCollection<PermissionNodeOutput> GetPermissionTreeOutput(MultiTenancySides side, ICollection<string> licPermissions);
 
-        /// <summary> 获取当前用户权限代码集合 </summary>
-        string[] GetUserPermissionCodes();
     }
 }

+ 6 - 5
VCommon.VApplication/Authorization/PermissionNode.cs

@@ -37,7 +37,7 @@ namespace VCommon.VApplication.Authorization
 
         public IReadOnlyList<PermissionNode> Children => _children;
 
-        internal PermissionNode(PermissionTree tree, string code, string name, string description, string nameForOperator, string descriptionForOperator, MultiTenancySides tenancySide = MultiTenancySides.Both)
+        internal PermissionNode(PermissionTree tree, string code, string name, string description, string nameForOperator, string descriptionForOperator, MultiTenancySides side = MultiTenancySides.Both)
         {
             _tree = tree;
             Code = code;
@@ -45,17 +45,18 @@ namespace VCommon.VApplication.Authorization
             Description = description;
             NameForOperator = nameForOperator;
             DescriptionForOperator = descriptionForOperator;
-            TenancySide = tenancySide;
+            TenancySide = side;
         }
 
-        public PermissionNode CreateChildNode(string code, string name, string description, string nameForOperator, string descriptionForOperator, MultiTenancySides tenancySide = MultiTenancySides.Both)
+        public PermissionNode CreateChildNode(string code, string name, string description = null, string nameForOperator = null, string descriptionForOperator = null, MultiTenancySides side = MultiTenancySides.Both)
         {
             if (_tree.CodeHashSet.Contains(code)) throw new ArgumentException($"重复的权限代码:{code},名称:{name}");
 
-            var node = new PermissionNode(_tree, code, name, description, nameForOperator, descriptionForOperator, tenancySide);
+            var node = new PermissionNode(_tree, code, name, description, nameForOperator, descriptionForOperator, side);
             _children.Add(node);
+            _tree._allNode.Add(node);
             _tree.CodeHashSet.Add(code);
             return node;
         }
     }
-}
+}

+ 2 - 6
VCommon.VApplication/Authorization/PermissionNodeOutput.cs

@@ -8,16 +8,12 @@ namespace VCommon.VApplication.Authorization
         public string Code { get; }
         public string Name { get; }
         public string Description { get; }
-        public string NameForOperator { get; }
-        public string DescriptionForOperator { get; }
 
-        internal PermissionNodeOutput(string code, string name, string description = null, string nameForOperator = null, string descriptionForOperator = null)
+        internal PermissionNodeOutput(string code, string name, string description = null)
         {
             Code = code;
             Name = name;
             Description = description;
-            NameForOperator = nameForOperator;
-            DescriptionForOperator = descriptionForOperator;
         }
     }
-}
+}

+ 22 - 12
VCommon.VApplication/Authorization/PermissionTree.cs

@@ -5,9 +5,11 @@ namespace VCommon.VApplication.Authorization
 {
     public class PermissionTree
     {
-        private readonly List<PermissionNode> _roots = new List<PermissionNode>();
+        private readonly List<PermissionNode> _roots = new();
 
-        private HashSet<string> _codeHashSet = new HashSet<string>();
+        private HashSet<string> _codeHashSet = new();
+
+        internal List<PermissionNode> _allNode = new();
 
         internal HashSet<string> CodeHashSet
         {
@@ -18,45 +20,53 @@ namespace VCommon.VApplication.Authorization
             }
         }
 
+        public IReadOnlyCollection<PermissionNode> AllNodes { get; private set; }
+
         public IReadOnlyCollection<PermissionNode> Roots => _roots;
 
-        public PermissionNode CreateRootNode(string code, string name, string description, string nameForOperator, string descriptionForOperator)
+        public PermissionNode CreateRootNode(string code, string name, string description = null, string nameForOperator = null, string descriptionForOperator = null, MultiTenancySides side = MultiTenancySides.Both)
         {
             if (CodeHashSet.Contains(code)) throw new ArgumentException($"重复的权限代码:{code},名称:{name}");
-            var node = new PermissionNode(this, code, name, description, nameForOperator, descriptionForOperator);
+            var node = new PermissionNode(this, code, name, description, nameForOperator, descriptionForOperator, side);
             _roots.Add(node);
+            _allNode.Add(node);
             CodeHashSet.Add(code);
             return node;
         }
 
-        public IReadOnlyCollection<PermissionNodeOutput> Filter(IReadOnlyCollection<string> licPerms)
+        public IReadOnlyCollection<PermissionNodeOutput> Filter(MultiTenancySides side, IReadOnlyCollection<string> licPerms)
         {
-            return FltTree(_roots, new HashSet<string>(licPerms));
+            return FltTree(_roots, side, new HashSet<string>(licPerms));
         }
 
-        private static IReadOnlyCollection<PermissionNodeOutput> FltTree(IReadOnlyCollection<PermissionNode> nodesFrom, HashSet<string> licPerms, List<PermissionNodeOutput> output = null)
+        private static IReadOnlyCollection<PermissionNodeOutput> FltTree(IReadOnlyCollection<PermissionNode> nodesFrom, MultiTenancySides side, IReadOnlySet<string> licPerms, List<PermissionNodeOutput> output = null)
         {
-            if (output == null) output = new List<PermissionNodeOutput>();
+            output ??= new List<PermissionNodeOutput>();
 
             foreach (var node in nodesFrom)
             {
                 if (!licPerms.Contains(node.Code)) continue;
+                if (node.TenancySide != side) continue;
+
+                var copy = side == MultiTenancySides.Tenant
+                    ? new PermissionNodeOutput(node.Code, node.Name, node.Description)
+                    : new PermissionNodeOutput(node.Code, node.NameForOperator ?? node.Name, node.DescriptionForOperator ?? node.Description);
 
-                var copy = new PermissionNodeOutput(node.Code, node.Name, node.Description, node.NameForOperator, node.DescriptionForOperator);
                 output.Add(copy);
 
-                FltTree(node.Children, licPerms, copy.Children);
+                FltTree(node.Children, side, licPerms, copy.Children);
             }
 
             return output;
         }
 
-        /// <summary> 初始化完成, 释放并返回重名检查集合, 禁止再加挂节点 </summary>
+        /// <summary> 完成初始化, 释放并返回重名检查集合, 提供扁平集合, 禁止再加挂节点 </summary>
         public HashSet<string> CompleteAdding()
         {
             var toReturn = _codeHashSet;
+            AllNodes = _allNode.ToArray();
             _codeHashSet = null;
             return toReturn;
         }
     }
-}
+}

+ 9 - 0
VCommon.VApplication/DataStore/IUserStore.cs

@@ -0,0 +1,9 @@
+using System;
+
+namespace VCommon.VApplication.DataStore
+{
+    public interface IUserStore
+    {
+        void ValidateToken(string token, out Guid? tenantId, out Guid userId);
+    }
+}

+ 1 - 1
VCommon.VApplication/Dto/IPassaveFilter.cs

@@ -1,6 +1,6 @@
 namespace VCommon.VApplication.Dto
 {
-    public interface IPassaveFilter
+    public interface IPassiveFilter
     {
         bool? IsEnable { get; set; }
     }

+ 14 - 0
VCommon.VApplication/EntityFrameworkCore/VAppEfDataFilters.cs

@@ -0,0 +1,14 @@
+namespace VCommon.VApplication.EntityFrameworkCore
+{
+    public class VAppEfDataFilters
+    {
+        /// <summary> 控制 IMustHaveTenant.TenantId 字段,默认启用:当前登录用户所属 TenantId </summary>
+        public const string MustHaveTenant = nameof(MustHaveTenant);
+
+        /// <summary> 控制 IMayHaveTenant.TenantId 字段,默认启用:当前登录用户所属 TenantId </summary>
+        public const string MayHaveTenant = nameof(MayHaveTenant);
+
+        /// <summary> 控制 IMustHaveOrg.OrgId 字段,默认启用:当前登录用户所属 OrgId </summary>
+        public const string MustHaveOrg = nameof(MustHaveOrg);
+    }
+}

+ 54 - 8
VCommon.VApplication/EntityFrameworkCore/VAppEfRepository.cs

@@ -1,6 +1,8 @@
-using System.Linq;
+using System.Collections.Generic;
+using System.Linq;
 using Unity;
 using VCommon.Ioc;
+using VCommon.VApplication.Authorization;
 using VCommon.VEntity;
 using VCommon.VEntityFrameworkCore;
 
@@ -14,31 +16,75 @@ namespace VCommon.VApplication.EntityFrameworkCore
         [Dependency]
         public IIocManager IocManager { get; set; }
 
+        private readonly Dictionary<string, bool> _filterState = new()
+        {
+            { VAppEfDataFilters.MayHaveTenant, true },
+            { VAppEfDataFilters.MustHaveTenant, true },
+            { VAppEfDataFilters.MustHaveOrg, true },
+        };
+
         public override VEfRepositoryBase<TDbContext, TForkEntity> ForkRepository<TForkEntity>()
         {
             return new VAppEfRepository<TDbContext, TForkEntity> { DbContext = DbContext };
         }
 
-        //TODO: Child Container
         protected override TDbContext ResolveDbContextInstance() => IocManager.Resolve<TDbContext>();
 
         protected override IQueryable<TEntity> ProcessFilters(IQueryable<TEntity> input)
         {
-            //TODO: More filters in VApplication
-            //    Org
-            //    MustHaveTenant
-            //    MayHaveTenant
+            if (_filterState[VAppEfDataFilters.MayHaveTenant] && typeof(TEntity).IsAssignableTo(typeof(IMayHaveTenant)))
+            {
+                input = input.Where(p => ((IMayHaveTenant)p).TenantId == VSession.TenantId);
+            }
+
+            if (_filterState[VAppEfDataFilters.MustHaveTenant] && typeof(TEntity).IsAssignableTo(typeof(IMustHaveTenant)))
+            {
+                input = input.Where(p => ((IMustHaveTenant)p).TenantId == VSession.TenantId);
+            }
+
+            if (_filterState[VAppEfDataFilters.MustHaveOrg]
+                && typeof(TEntity).IsAssignableTo(typeof(IMustHaveOrg))
+                && IocManager.TryResolve(out IOrgManager orgManager) && orgManager.Enabled)
+            {
+                var visionOrg = orgManager.GetUserVisionOrg(VSession.TenantId, VSession.UserId);
+                input = input.Where(p => visionOrg.Contains(((IMustHaveOrg)p).OrgId));
+            }
 
             return base.ProcessFilters(input);
         }
 
         public override TEntity Add(TEntity entity)
         {
-            //TODO: More filters in VApplication
+            if (IsFilterEnabled(VAppEfDataFilters.MustHaveTenant) && entity is IMustHaveTenant mte) mte.TenantId = VSession.GetTenantId();
 
-            if (IsFilterEnabled(VEfDataFilters.MustHaveTenant) && entity is IMustHaveTenant mte) mte.TenantId = VSession.GetTenantId();
+            if (_filterState[VAppEfDataFilters.MustHaveOrg]
+                && typeof(TEntity).IsAssignableTo(typeof(IMustHaveOrg))
+                && IocManager.TryResolve(out IOrgManager orgManager) && orgManager.Enabled)
+            {
+                var visionOrg = orgManager.GetUserVisionOrg(VSession.TenantId, VSession.UserId);
+                if (false == visionOrg.Contains(((IMustHaveOrg)entity).OrgId)) throw new VApplicationAuthException("拒绝访问:您没有权限访问该组织", AuthReason.AccessDenied);
+            }
 
             return base.Add(entity);
         }
+
+        public override void EnableFilter(string filterName)
+        {
+            if (_filterState.ContainsKey(filterName)) _filterState[filterName] = true;
+            else base.EnableFilter(filterName);
+        }
+
+        public override void DisableFilter(string filterName)
+        {
+            if (_filterState.ContainsKey(filterName)) _filterState[filterName] = false;
+            else base.EnableFilter(filterName);
+        }
+
+        public override bool IsFilterEnabled(string filterName)
+        {
+            return _filterState.ContainsKey(filterName)
+                ? _filterState[filterName]
+                : base.IsFilterEnabled(filterName);
+        }
     }
 }

+ 2 - 0
VCommon.VApplication/IVSession.cs

@@ -7,6 +7,8 @@ namespace VCommon.VApplication
         Guid? UserId { get; }
         Guid? TenantId { get; }
 
+        string Token { get; }
+
         void DemandAuth();
 
         public Guid GetUserId()

+ 1 - 1
VCommon.VApplication/Linq.Expressions/PredicateExpressionBuilderExtensionMethods.cs

@@ -14,7 +14,7 @@ namespace VCommon.VApplication.Linq.Expressions
                 : me.Between(selector, filter.BeginTime, filter.EndTime);
         }
 
-        public static PredicateWrap<T> FilterByEnable<T>(this PredicateBuilder<T> me, IPassaveFilter filter) where T : IPassive
+        public static PredicateWrap<T> FilterByEnable<T>(this PredicateBuilder<T> me, IPassiveFilter filter) where T : IPassive
         {
             return true != filter?.IsEnable.HasValue ? null
                 : me.Equal(ExpressionHelper.Property<T, bool>(nameof(IPassive.IsEnable)), filter.IsEnable.Value);

+ 17 - 0
VCommon.VApplication/VEmptySession.cs

@@ -0,0 +1,17 @@
+using System;
+using VCommon.Ioc;
+
+namespace VCommon.VApplication
+{
+    public class VEmptySession : IVSession, ISingletonIocClass
+    {
+        public Guid? UserId { get; }
+        public Guid? TenantId { get; }
+        public string Token { get; }
+
+        public void DemandAuth()
+        {
+
+        }
+    }
+}

+ 2 - 2
VCommon.VAutoMapper/Internals/MiddleClass.cs

@@ -9,11 +9,11 @@ using VCommon.Reflection;
 
 namespace VCommon.VAutoMapper.Internals
 {
-    //REF: stackoverflow.com/a/3862241/2430943
+    //REF: StackOverflow.com/a/3862241/2430943
 
     internal static class MiddleClass
     {
-        private static readonly string NameSpace = $"{nameof(VCommon)}.{nameof(VCommon.VAutoMapper)}.{nameof(MiddleClass)}";
+        private static readonly string NameSpace = $"{nameof(VCommon)}.{nameof(VCommon.VAutoMapper)}.MiddleClasses.{nameof(MiddleClass)}";
         private static readonly ModuleBuilder ModuleBuilder;
 
         static MiddleClass()

+ 8 - 6
VCommon.VAutoMapper/Internals/MiddleMapper.cs

@@ -16,8 +16,10 @@ namespace VCommon.VAutoMapper.Internals
 
         private static readonly Type DtoType = typeof(TDto);
 
-        public static TDto[] Projection<TEntity>(IQueryable<TEntity> queryable)
+        public static TDto[] ProjectionToArray<TEntity>(IQueryable<TEntity> queryable)
         {
+            Func<object, object> mp;
+
             lock (MiddleClasses)
             {
                 lock (MiddleProjection)
@@ -26,14 +28,14 @@ namespace VCommon.VAutoMapper.Internals
                     if (false == MiddleClasses.TryGetValue(entityType, out var mt))
                         mt = MiddleClasses[entityType] = MiddleClass.Create(entityType, DtoType);
 
-                    if (false == MiddleProjection.TryGetValue(entityType, out var mp))
+                    if (false == MiddleProjection.TryGetValue(entityType, out mp))
                         mp = MiddleProjection[entityType] = CreateMiddleProjection(entityType, mt);
-
-                    var arr = mp(queryable);
-                    var result = arr.MapTo<TDto[]>();
-                    return result;
                 }
             }
+
+            var arr = mp(queryable);
+            var result = arr.MapTo<TDto[]>();
+            return result;
         }
 
         private static Func<object, object> CreateMiddleProjection(Type entityType, Type mt)

+ 9 - 2
VCommon.VAutoMapper/VAutoMapper.cs

@@ -99,7 +99,7 @@ namespace VCommon.VAutoMapper
                 var expression = Expression.Lambda<Func<object, object>>(callJson, paramFrom);
                 var func = expression.Compile();
 
-                cfg.ForMember(fromProp.Name, x => x.MapFrom(obj=>func(obj)));
+                cfg.ForMember(fromProp.Name, x => x.MapFrom(obj => func(obj)));
             }
         }
 
@@ -112,8 +112,15 @@ namespace VCommon.VAutoMapper
         public static TD[] ProjectionToArray<TF, TD>(this IQueryable<TF> queryable)
         {
             return PolyfillTypes.Contains(typeof(TD))
-                ? MiddleMapper<TD>.Projection(queryable)
+                ? MiddleMapper<TD>.ProjectionToArray(queryable)
                 : queryable.ProjectTo<TD>(Config.Config).ToArray();
         }
+
+        public static TD ProjectionFirstOrDefault<TF, TD>(this IQueryable<TF> queryable)
+        {
+            return PolyfillTypes.Contains(typeof(TD))
+                ? MiddleMapper<TD>.ProjectionToArray(queryable).FirstOrDefault()
+                : queryable.ProjectTo<TD>(Config.Config).FirstOrDefault();
+        }
     }
 }

+ 2 - 1
VCommon.VEntity/IMustHaveOrg.cs

@@ -2,9 +2,10 @@
 
 namespace VCommon.VEntity
 {
-    //TODO: 移动到 VApplication.VEntity
     public interface IMustHaveOrg
     {
         Guid OrgId { get; set; }
     }
+
+  
 }

+ 5 - 8
VCommon.VEntity/VEntityBase.cs

@@ -6,16 +6,13 @@ namespace VCommon.VEntity
 {
     public abstract class VEntityBase
     {
-        private string _keyField; //EF Core Trick? must difference with prop name for init
+        private Guid? _keyField; //EF Core Trick? must difference with prop name for init
 
-        [Key, MinLength(36), MaxLength(36), DatabaseGenerated(DatabaseGeneratedOption.None)]
-        public string Id
+        [Key]
+        [DatabaseGenerated(DatabaseGeneratedOption.None)]
+        public Guid Id
         {
-            get
-            {
-                if (string.IsNullOrWhiteSpace(_keyField)) _keyField = Guid.NewGuid().ToString();
-                return _keyField;
-            }
+            get => _keyField ??= Guid.NewGuid();
             set => _keyField = value;
         }
     }

+ 0 - 39
VCommon.VEntityFrameworkCore.Tests/Migrations/20210622032917_CreateDataBaseTest.Designer.cs

@@ -1,39 +0,0 @@
-// <auto-generated />
-
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Infrastructure;
-using Microsoft.EntityFrameworkCore.Migrations;
-using VCommon.VEntityFrameworkCore.Tests.Efc;
-
-namespace VCommon.VEntityFrameworkCore.Tests.Migrations
-{
-    [DbContext(typeof(TestDbContext))]
-    [Migration("20210622032917_CreateDataBaseTest")]
-    partial class CreateDataBaseTest
-    {
-        protected override void BuildTargetModel(ModelBuilder modelBuilder)
-        {
-#pragma warning disable 612, 618
-            modelBuilder
-                .HasAnnotation("Relational:MaxIdentifierLength", 64)
-                .HasAnnotation("ProductVersion", "5.0.7");
-
-            modelBuilder.Entity("VCommon.VEntityFrameworkCore.TestWeb.TestEntity", b =>
-                {
-                    b.Property<byte[]>("Id")
-                        .HasColumnType("varbinary(16)");
-
-                    b.Property<bool>("IsAbolish")
-                        .HasColumnType("tinyint(1)");
-
-                    b.Property<string>("Name")
-                        .HasColumnType("text");
-
-                    b.HasKey("Id");
-
-                    b.ToTable("TestEntities");
-                });
-#pragma warning restore 612, 618
-        }
-    }
-}

+ 0 - 44
VCommon.VEntityFrameworkCore.Tests/Migrations/20210626092232_AddFilterField.Designer.cs

@@ -1,44 +0,0 @@
-// <auto-generated />
-using System;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Infrastructure;
-using Microsoft.EntityFrameworkCore.Migrations;
-using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
-using VCommon.VEntityFrameworkCore.Tests;
-using VCommon.VEntityFrameworkCore.Tests.Efc;
-
-namespace VCommon.VEntityFrameworkCore.Tests.Migrations
-{
-    [DbContext(typeof(TestDbContext))]
-    [Migration("20210626092232_AddFilterField")]
-    partial class AddFilterField
-    {
-        protected override void BuildTargetModel(ModelBuilder modelBuilder)
-        {
-#pragma warning disable 612, 618
-            modelBuilder
-                .HasAnnotation("Relational:MaxIdentifierLength", 64)
-                .HasAnnotation("ProductVersion", "5.0.7");
-
-            modelBuilder.Entity("VCommon.VEntityFrameworkCore.Tests.TestEntity", b =>
-                {
-                    b.Property<byte[]>("Id")
-                        .HasColumnType("varbinary(16)");
-
-                    b.Property<bool>("IsAbolish")
-                        .HasColumnType("tinyint(1)");
-
-                    b.Property<bool>("IsEnable")
-                        .HasColumnType("tinyint(1)");
-
-                    b.Property<string>("Name")
-                        .HasColumnType("text");
-
-                    b.HasKey("Id");
-
-                    b.ToTable("TestEntities");
-                });
-#pragma warning restore 612, 618
-        }
-    }
-}

+ 0 - 24
VCommon.VEntityFrameworkCore.Tests/Migrations/20210626092232_AddFilterField.cs

@@ -1,24 +0,0 @@
-using Microsoft.EntityFrameworkCore.Migrations;
-
-namespace VCommon.VEntityFrameworkCore.Tests.Migrations
-{
-    public partial class AddFilterField : Migration
-    {
-        protected override void Up(MigrationBuilder migrationBuilder)
-        {
-            migrationBuilder.AddColumn<bool>(
-                name: "IsEnable",
-                table: "TestEntities",
-                type: "tinyint(1)",
-                nullable: false,
-                defaultValue: false);
-        }
-
-        protected override void Down(MigrationBuilder migrationBuilder)
-        {
-            migrationBuilder.DropColumn(
-                name: "IsEnable",
-                table: "TestEntities");
-        }
-    }
-}

+ 0 - 50
VCommon.VEntityFrameworkCore.Tests/Migrations/20210626094351_AddAuditField.Designer.cs

@@ -1,50 +0,0 @@
-// <auto-generated />
-using System;
-using Microsoft.EntityFrameworkCore;
-using Microsoft.EntityFrameworkCore.Infrastructure;
-using Microsoft.EntityFrameworkCore.Migrations;
-using Microsoft.EntityFrameworkCore.Storage.ValueConversion;
-using VCommon.VEntityFrameworkCore.Tests;
-using VCommon.VEntityFrameworkCore.Tests.Efc;
-
-namespace VCommon.VEntityFrameworkCore.Tests.Migrations
-{
-    [DbContext(typeof(TestDbContext))]
-    [Migration("20210626094351_AddAuditField")]
-    partial class AddAuditField
-    {
-        protected override void BuildTargetModel(ModelBuilder modelBuilder)
-        {
-#pragma warning disable 612, 618
-            modelBuilder
-                .HasAnnotation("Relational:MaxIdentifierLength", 64)
-                .HasAnnotation("ProductVersion", "5.0.7");
-
-            modelBuilder.Entity("VCommon.VEntityFrameworkCore.Tests.TestEntity", b =>
-                {
-                    b.Property<byte[]>("Id")
-                        .HasColumnType("varbinary(16)");
-
-                    b.Property<DateTime>("CreationTime")
-                        .HasColumnType("datetime");
-
-                    b.Property<bool>("IsAbolish")
-                        .HasColumnType("tinyint(1)");
-
-                    b.Property<bool>("IsEnable")
-                        .HasColumnType("tinyint(1)");
-
-                    b.Property<DateTime?>("LastModificationTime")
-                        .HasColumnType("datetime");
-
-                    b.Property<string>("Name")
-                        .HasColumnType("text");
-
-                    b.HasKey("Id");
-
-                    b.ToTable("TestEntities");
-                });
-#pragma warning restore 612, 618
-        }
-    }
-}

+ 0 - 35
VCommon.VEntityFrameworkCore.Tests/Migrations/20210626094351_AddAuditField.cs

@@ -1,35 +0,0 @@
-using System;
-using Microsoft.EntityFrameworkCore.Migrations;
-
-namespace VCommon.VEntityFrameworkCore.Tests.Migrations
-{
-    public partial class AddAuditField : Migration
-    {
-        protected override void Up(MigrationBuilder migrationBuilder)
-        {
-            migrationBuilder.AddColumn<DateTime>(
-                name: "CreationTime",
-                table: "TestEntities",
-                type: "datetime",
-                nullable: false,
-                defaultValue: new DateTime(1, 1, 1, 0, 0, 0, 0, DateTimeKind.Unspecified));
-
-            migrationBuilder.AddColumn<DateTime>(
-                name: "LastModificationTime",
-                table: "TestEntities",
-                type: "datetime",
-                nullable: true);
-        }
-
-        protected override void Down(MigrationBuilder migrationBuilder)
-        {
-            migrationBuilder.DropColumn(
-                name: "CreationTime",
-                table: "TestEntities");
-
-            migrationBuilder.DropColumn(
-                name: "LastModificationTime",
-                table: "TestEntities");
-        }
-    }
-}

+ 0 - 32
VCommon.VEntityFrameworkCore.Tests/Migrations/20210627052532_ChangeKeyField.cs

@@ -1,32 +0,0 @@
-using System;
-using Microsoft.EntityFrameworkCore.Migrations;
-
-namespace VCommon.VEntityFrameworkCore.Tests.Migrations
-{
-    public partial class ChangeKeyField : Migration
-    {
-        protected override void Up(MigrationBuilder migrationBuilder)
-        {
-            migrationBuilder.AlterColumn<string>(
-                name: "Id",
-                table: "TestEntities",
-                type: "varchar(36)",
-                maxLength: 36,
-                nullable: false,
-                oldClrType: typeof(byte[]),
-                oldType: "varbinary(16)");
-        }
-
-        protected override void Down(MigrationBuilder migrationBuilder)
-        {
-            migrationBuilder.AlterColumn<byte[]>(
-                name: "Id",
-                table: "TestEntities",
-                type: "varbinary(16)",
-                nullable: false,
-                oldClrType: typeof(string),
-                oldType: "varchar(36)",
-                oldMaxLength: 36);
-        }
-    }
-}

+ 4 - 5
VCommon.VEntityFrameworkCore.Tests/Migrations/20210627052532_ChangeKeyField.Designer.cs

@@ -9,8 +9,8 @@ using VCommon.VEntityFrameworkCore.Tests.Efc;
 namespace VCommon.VEntityFrameworkCore.Tests.Migrations
 {
     [DbContext(typeof(TestDbContext))]
-    [Migration("20210627052532_ChangeKeyField")]
-    partial class ChangeKeyField
+    [Migration("20210715014528_CreateDatabase")]
+    partial class CreateDatabase
     {
         protected override void BuildTargetModel(ModelBuilder modelBuilder)
         {
@@ -21,9 +21,8 @@ namespace VCommon.VEntityFrameworkCore.Tests.Migrations
 
             modelBuilder.Entity("VCommon.VEntityFrameworkCore.Tests.Entities.TestEntity", b =>
                 {
-                    b.Property<string>("Id")
-                        .HasMaxLength(36)
-                        .HasColumnType("varchar(36)");
+                    b.Property<Guid>("Id")
+                        .HasColumnType("binary(16)");
 
                     b.Property<DateTime>("CreationTime")
                         .HasColumnType("datetime");

+ 8 - 4
VCommon.VEntityFrameworkCore.Tests/Migrations/20210622032917_CreateDataBaseTest.cs

@@ -1,8 +1,9 @@
-using Microsoft.EntityFrameworkCore.Migrations;
+using System;
+using Microsoft.EntityFrameworkCore.Migrations;
 
 namespace VCommon.VEntityFrameworkCore.Tests.Migrations
 {
-    public partial class CreateDataBaseTest : Migration
+    public partial class CreateDatabase : Migration
     {
         protected override void Up(MigrationBuilder migrationBuilder)
         {
@@ -10,9 +11,12 @@ namespace VCommon.VEntityFrameworkCore.Tests.Migrations
                 name: "TestEntities",
                 columns: table => new
                 {
-                    Id = table.Column<byte[]>(type: "varbinary(16)", nullable: false),
+                    Id = table.Column<Guid>(type: "binary(16)", nullable: false),
                     Name = table.Column<string>(type: "text", nullable: true),
-                    IsAbolish = table.Column<bool>(type: "tinyint(1)", nullable: false)
+                    IsAbolish = table.Column<bool>(type: "tinyint(1)", nullable: false),
+                    IsEnable = table.Column<bool>(type: "tinyint(1)", nullable: false),
+                    CreationTime = table.Column<DateTime>(type: "datetime", nullable: false),
+                    LastModificationTime = table.Column<DateTime>(type: "datetime", nullable: true)
                 },
                 constraints: table =>
                 {

+ 2 - 3
VCommon.VEntityFrameworkCore.Tests/Migrations/TestDbContextModelSnapshot.cs

@@ -19,9 +19,8 @@ namespace VCommon.VEntityFrameworkCore.Tests.Migrations
 
             modelBuilder.Entity("VCommon.VEntityFrameworkCore.Tests.Entities.TestEntity", b =>
                 {
-                    b.Property<string>("Id")
-                        .HasMaxLength(36)
-                        .HasColumnType("varchar(36)");
+                    b.Property<Guid>("Id")
+                        .HasColumnType("binary(16)");
 
                     b.Property<DateTime>("CreationTime")
                         .HasColumnType("datetime");

+ 1 - 10
VCommon.VEntityFrameworkCore/VEfDataFilters.cs

@@ -8,15 +8,6 @@
         /// <summary> 控制 IPassive.IsEnable 字段,默认启用:true </summary>
         public const string Passive = nameof(Passive);  
         
-        //TODO: 将下面的过滤器移动到 VApplication
-
-        /// <summary> 控制 IMustHaveTenant.TenantId 字段,默认启用:当前登录用户所属 TenantId </summary>
-        public const string MustHaveTenant = nameof(MustHaveTenant);
-
-        /// <summary> 控制 IMayHaveTenant.TenantId 字段,默认启用:当前登录用户所属 TenantId </summary>
-        public const string MayHaveTenant = nameof(MayHaveTenant);
-
-        /// <summary> 控制 IMustHaveOrg.OrgId 字段,默认启用:当前登录用户所属 OrgId </summary>
-        public const string MustHaveOrg = nameof(MustHaveOrg);
+       
     }
 }

+ 5 - 6
VCommon.VEntityFrameworkCore/VEfRepositoryBase.cs

@@ -35,7 +35,6 @@ namespace VCommon.VEntityFrameworkCore
                 input = input.Where(p => ((IPassive)p).IsEnable == false);
             }
 
-
             return input;
         }
 
@@ -45,8 +44,11 @@ namespace VCommon.VEntityFrameworkCore
 
         protected DbSet<TEntity> DbSet => DbContext.Set<TEntity>();
 
-        public bool IsFilterEnabled(string filterName) => _filterState[filterName];
+        public virtual void DisableFilter(string filterName) => _filterState[filterName] = false;
+
+        public virtual void EnableFilter(string filterName) => _filterState[filterName] = true;
 
+        public virtual bool IsFilterEnabled(string filterName) => _filterState[filterName];
 
         public virtual IQueryable<TEntity> QueryNoTracking(Expression<Func<TEntity, bool>> queryExpression = null)
         {
@@ -64,9 +66,6 @@ namespace VCommon.VEntityFrameworkCore
             return null == queryExpression ? source : source.Where(queryExpression);
         }
 
-        public virtual void DisableFilter(string filterName) => _filterState[filterName] = false;
-
-        public virtual void EnableFilter(string filterName) => _filterState[filterName] = true;
 
         public virtual void Delete(TEntity entity) => DbSet.Remove(entity);
 
@@ -79,7 +78,7 @@ namespace VCommon.VEntityFrameworkCore
             return null == expression ? source.Any() : source.Any(expression);
         }
 
-        public TEntity GetEntityOrDefault(string id) => ProcessFilters(DbSet).FirstOrDefault(p => p.Id == id);
+        public TEntity GetEntityOrDefault(Guid id) => ProcessFilters(DbSet).FirstOrDefault(p => p.Id == id);
 
         public TEntity GetEntityOrDefault(Expression<Func<TEntity, bool>> expression = null)
         {

+ 41 - 36
VCommon.VOpenApi.VAspNetCore/ApiMiddleware.cs

@@ -111,7 +111,7 @@ namespace VCommon.VOpenApi.VAspNetCore
                 //put session dependency
                 child.RegisterInstanceToContainer(context);
                 //override session to child container from root
-                child.RegisterManually<VSession>();
+                child.RegisterManually<VAspNetCoreSession>();
 
                 try
                 {
@@ -139,44 +139,49 @@ namespace VCommon.VOpenApi.VAspNetCore
             //500:服务器内部错误 *其他
 
             context.Response.ContentType = "application/json";
-            if (error is VApiArgumentException apiArgumentException)
+            switch (error)
             {
-                context.Response.StatusCode = 400;
-                await context.Response.WriteAsync(VJsonSerializer.Serialize(new { apiArgumentException.Message }));
-            }
-            else if (error is VApplicationModelValidationException modelValidationException)
-            {
-                context.Response.StatusCode = 422;
-                await context.Response.WriteAsync(VJsonSerializer.Serialize(new { modelValidationException.Message, modelValidationException.Results }));
-            }
-            else if (error is VApplicationAuthException authException)
-            {
-                context.Response.StatusCode = authException.Reason == AuthReason.AuthRequired ? 401 : 403;
-                await context.Response.WriteAsync(VJsonSerializer.Serialize(new { authException.Message }));
-            }
-            else
-            {
-                context.Response.StatusCode = 500;
-
-                string response;
-                if (false == _isDebuggingEnabled)
-                {
-                    response = VJsonSerializer.Serialize(new { Message = "Server internal error" });
-                }
-                else
-                {
-                    try
+                case VFriendlyException friendlyException:
+                    context.Response.StatusCode = friendlyException.StatusCode;
+                    await context.Response.WriteAsync(VJsonSerializer.Serialize(new { friendlyException.Message }));
+                    break;
+                case VApiArgumentException apiArgumentException:
+                    context.Response.StatusCode = 400;
+                    await context.Response.WriteAsync(VJsonSerializer.Serialize(new { apiArgumentException.Message }));
+                    break;
+                case VApplicationModelValidationException modelValidationException:
+                    context.Response.StatusCode = 422;
+                    await context.Response.WriteAsync(VJsonSerializer.Serialize(new { modelValidationException.Message, modelValidationException.Results }));
+                    break;
+                case VApplicationAuthException authException:
+                    context.Response.StatusCode = authException.Reason == AuthReason.AuthRequired ? 401 : 403;
+                    await context.Response.WriteAsync(VJsonSerializer.Serialize(new { authException.Message }));
+                    break;
+                default:
                     {
-                        response = VJsonSerializer.Serialize(error);
+                        context.Response.StatusCode = 500;
+
+                        string response;
+                        if (false == _isDebuggingEnabled)
+                        {
+                            response = VJsonSerializer.Serialize(new { Message = "Server internal error" });
+                        }
+                        else
+                        {
+                            try
+                            {
+                                response = VJsonSerializer.Serialize(error);
+                            }
+                            catch (Exception exception)
+                            {
+                                Logger.Error("ApiMiddleware:Exception json serializer fail", exception);
+                                response = VJsonSerializer.Serialize(new { Message = error.ToString() });
+                            }
+                        }
+
+                        await context.Response.WriteAsync(response);
+                        break;
                     }
-                    catch (Exception exception)
-                    {
-                        Logger.Error("ApiMiddleware:Exception json serializer fail", exception);
-                        response = VJsonSerializer.Serialize(new { Message = error.ToString() });
-                    }
-                }
-
-                await context.Response.WriteAsync(response);
             }
         }
     }

+ 0 - 12
VCommon.VOpenApi.VAspNetCore/IUserTokenStore.cs

@@ -1,12 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Threading.Tasks;
-
-namespace VCommon.VOpenApi.VAspNetCore
-{
-    public interface IUserTokenStore
-    {
-        void Validate(string token, out Guid? tenantId, out Guid? userId);
-    }
-}

+ 22 - 5
VCommon.VOpenApi.VAspNetCore/VSession.cs

@@ -2,26 +2,29 @@
 using System;
 using VCommon.Ioc;
 using VCommon.VApplication;
+using VCommon.VApplication.DataStore;
 
 namespace VCommon.VOpenApi.VAspNetCore
 {
-    public class VSession : IVSession, ISingletonIocClass
+    public class VAspNetCoreSession : IVSession, ISingletonIocClass
     {
         private const string AuthorizationHeader = "Authorization";
         private const string TokenHeaderPart = "Token";
 
         private readonly HttpContext _context;
-        private readonly IUserTokenStore _tokenStore;
+        private readonly IUserStore _store;
 
         private bool _isTokenChecked;
 
         private Guid? _tenantId;
         private Guid? _userId;
 
-        internal VSession(HttpContext context, IUserTokenStore tokenStore)
+        private string _token;
+
+        internal VAspNetCoreSession(HttpContext context, IUserStore store)
         {
             _context = context;
-            _tokenStore = tokenStore;
+            _store = store;
         }
 
         private void EnsureTokenCheck()
@@ -42,7 +45,12 @@ namespace VCommon.VOpenApi.VAspNetCore
             }
 
             //验证Token
-            if (null != token) _tokenStore.Validate(token, out _tenantId, out _userId);
+            if (null != token)
+            {
+                _store.ValidateToken(token, out _tenantId, out var uid);
+                _userId = uid;
+                _token = token;
+            }
 
             _isTokenChecked = true;
         }
@@ -65,6 +73,15 @@ namespace VCommon.VOpenApi.VAspNetCore
             }
         }
 
+        public string Token
+        {
+            get
+            {
+                EnsureTokenCheck();
+                return _token;
+            }
+        }
+
         public void DemandAuth()
         {
             EnsureTokenCheck();

+ 18 - 0
VCommon.VOpenApi.VAspNetCore/VFriendlyException.cs

@@ -0,0 +1,18 @@
+using System;
+
+namespace VCommon.VOpenApi.VAspNetCore
+{
+    public class VFriendlyException : Exception
+    {
+        public int StatusCode { get; set; } = 400;
+
+        public VFriendlyException(string message) : base(message)
+        {
+        }
+
+        public VFriendlyException(string message, int statusCode) : base(message)
+        {
+            StatusCode = statusCode;
+        }
+    }
+}