• .NET 云原生架构师训练营(权限系统 代码实现 EntityAccess)学习笔记


    目录

    • 开发任务
    • 代码实现

    开发任务

    • DotNetNB.Security.Core:定义 core,models,Istore;实现 default memory store
    • DotNetNB.Security.EntityAccess:扫描 entities;添加 ef savechanges interceptor

    代码实现

    我们现在已经通过 ActionResourceProvider 完成了 action 的扫描,生成了 ResourceModel,需要持久化到 IResourceStore,持久化之后才可以将它们绑定到用户,角色

    由于 ActionAccess 是一个类库,提供了一些比较零散的功能,所以需要添加一个扩展方法把功能组装起来,在 host 启动的时候执行 action 的扫描

    using Microsoft.Extensions.DependencyInjection;
    
    namespace DotNetNB.Security.Core.Extensions
    {
        public static class ServiceCollectionExtensions
        {
            public static IServiceCollection AddSecurity(this IServiceCollection services)
            {
                services.AddHostedService<ResourceProviderHostedService>();
                return services;
            }
        }
    }
    

    ResourceProviderHostedService 继承自 IHostedService,有一个 StartAsync 和一个 StopAsync 方法

    using Microsoft.Extensions.Hosting;
    
    namespace DotNetNB.Security.Core
    {
        public class ResourceProviderHostedService : IHostedService
        {
            public async Task StartAsync(CancellationToken cancellationToken)
            {
    
            }
    
            public async Task StopAsync(CancellationToken cancellationToken)
            {
    
            }
        }
    }
    

    新建一个示例的 api 项目 DotNetNB.WebApplication,在这个 api 项目里面使用我们的 dll 要足够简单,就像使用 asp .net core 的 api 一样

    添加 DotNetNB.Security.Core 的项目引用之后,可以直接在 Program.cs 中调用扩展方法

    using DotNetNB.Security.Core.Extensions;
    
    ...
    
    builder.Services.AddSecurity();
    

    在启动扫描的时候,Security.Core 并不知道外部的 host 里面有哪些 action provider,所以需要注册进来,需要构建一个 builder

    同时需要一个配置 options 告诉我们它是来自哪个包,是 ActionAccess,还是 EntityAccess

    参照 MvcOptions

    builder.Services.AddControllers(options => {});
    

    它是一个 Action 的委托

    public static IMvcBuilder AddControllers(
      this IServiceCollection services,
      Action<MvcOptions>? configure)
    {
      IMvcCoreBuilder builder = services != null ? MvcServiceCollectionExtensions.AddControllersCore(services) : throw new ArgumentNullException(nameof (services));
      if (configure != null)
        builder.AddMvcOptions(configure);
      return (IMvcBuilder) new MvcBuilder(builder.Services, builder.PartManager);
    }
    

    于是乎我们在 AddSecurity 添加一个入参

    public static IServiceCollection AddSecurity(this IServiceCollection services, Action<SecurityOption>? configure)
    

    SecurityOption

    using Microsoft.Extensions.DependencyInjection;
    
    namespace DotNetNB.Security.Core.Extensions
    {
        public class SecurityOption
        {
            public IServiceCollection Services { get; set; }
        }
    }
    

    在调用 AddSecurity 扩展方法的时候通过 SecurityOption 进行配置,这样所有对外的 api 只需要做这一个配置就可以把两个包的所有功能引用进去

    builder.Services.AddSecurity(options =>
    {
        options.AddActionAccess();
        options.AddEntityAccess<DBContext>();
    });
    

    参考 MvcCoreServiceCollectionExtensions 的 AddMvcCoreServices 方法

    internal static void AddMvcCoreServices(IServiceCollection services)
    {
        //
        // Options
        //
        services.TryAddEnumerable(
            ServiceDescriptor.Transient<IConfigureOptions<MvcOptions>, MvcCoreMvcOptionsSetup>());
        
        ...
    }
    

    在 ActionAccess 中添加一个扩展方法 AddActionAccessControl,将 IResourceProvider 添加进去,这样就可以在 ResourceProviderHostedService 中读取到

    using DotNetNB.Security.Core;
    using DotNetNB.Security.Core.Extensions;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.DependencyInjection.Extensions;
    
    namespace DotNetNB.Security.ActionAccess
    {
        public static class SecurityOptionExtensions
        {
            public static SecurityOption AddActionAccessControl(this SecurityOption option)
            {
                option.Services.TryAddEnumerable(ServiceDescriptor.Transient<IResourceProvider, ActionResourceProvider>());
                return option;
            }
        }
    }
    

    在 ResourceProviderHostedService 的构造函数中读取 IServiceProvider

    using Microsoft.Extensions.Hosting;
    
    namespace DotNetNB.Security.Core
    {
        public class ResourceProviderHostedService : IHostedService
        {
            private readonly IServiceProvider[] _serviceProviders;
    
            public ResourceProviderHostedService(IServiceProvider[] serviceProviders)
            {
                _serviceProviders = serviceProviders;
            }
    
            public async Task StartAsync(CancellationToken cancellationToken)
            {
    
            }
    
            public async Task StopAsync(CancellationToken cancellationToken)
            {
    
            }
        }
    }
    

    在 EntityAccess 中同样添加一个扩展方法 AddEntityAccessControl

    using DotNetNB.Security.Core;
    using DotNetNB.Security.Core.Extensions;
    using Microsoft.Extensions.DependencyInjection;
    using Microsoft.Extensions.DependencyInjection.Extensions;
    
    namespace DotNetNB.Security.EntityAccess
    {
        public static class SecurityOptionExtensions
        {
            public static SecurityOption AddEntityAccessControl(this SecurityOption option)
            {
                option.Services.TryAddEnumerable(ServiceDescriptor.Transient<IResourceProvider, EntityResourceProvider>());
                return option;
            }
        }
    }
    

    EntityResourceProvider 继承 IResourceProvider

    using DotNetNB.Security.Core;
    using DotNetNB.Security.Core.Models;
    
    namespace DotNetNB.Security.EntityAccess
    {
        public class EntityResourceProvider : IResourceProvider
        {
            public async Task<IEnumerable<Resource>> ExecuteAsync()
            {
                return new List<Resource>();
            }
        }
    }
    

    完成之后在 DotNetNB.WebApplication 中添加项目引用,就可以进行配置

    builder.Services.AddSecurity(options =>
    {
        options.AddActionAccessControl()
            .AddEntityAccessControl();
    });
    

    后面再完善 AddEntityAccessControl 加入 DBContext

    GitHub源码链接:

    https://github.com/MingsonZheng/dotnetnb.security

    课程链接

    https://appsqsyiqlk5791.h5.xiaoeknow.com/v1/course/video/v_5f39bdb8e4b01187873136cf?type=2

    知识共享许可协议

    本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

    欢迎转载、使用、重新发布,但务必保留文章署名 郑子铭 (包含链接: http://www.cnblogs.com/MingsonZheng/ ),不得用于商业目的,基于本文修改后的作品务必以相同的许可发布。

    如有任何疑问,请与我联系 (MingsonZheng@outlook.com) 。

  • 相关阅读:
    将Tomcat配置到你的mac电脑上,命令行启动tomcat
    Java反射获取字节码以及判断类型
    mysql那些事
    Hibernate 一对一中的一些问题
    Java long类型和Long类型的那些事
    java中的多线程
    Struts2:java.lang.NoSuchFieldException: resourceEntries at java.lang.Class.getDeclaredField(Class.java:1901)
    生产者-消费者模式
    并行程序设计模式--Master-Worker模式
    Ibatis的类型处理器TypeHandler解析
  • 原文地址:https://www.cnblogs.com/MingsonZheng/p/15902528.html
Copyright © 2020-2023  润新知