.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) 。
- .NET 云原生架构师训练营(权限系统 RGCA 开发任务)--学习笔记
- .NET 云原生架构师训练营(模块二 基础巩固 路由与终结点)--学习笔记
- .NET 云原生架构师训练营(模块二 基础巩固 MVC终结点)--学习笔记
- .NET 云原生架构师训练营(模块二 基础巩固 EF Core 基础与配置)--学习笔记
- .NET 云原生架构师训练营(模块二 基础巩固 EF Core 关系)--学习笔记
- .NET 云原生架构师训练营(模块二 基础巩固 RabbitMQ Masstransit 详解)--学习笔记
- .NET 云原生架构师训练营(模块二 基础巩固 敏捷开发)--学习笔记
- .NET 云原生架构师训练营(模块二 基础巩固 MongoDB API重构)--学习笔记
- .NET 云原生架构师训练营(模块二 基础巩固 日志)--学习笔记
- .NET 云原生架构师训练营(模块二 基础巩固 HTTP管道与中间件)--学习笔记
- .NET 云原生架构师训练营(模块二 基础巩固 RabbitMQ HelloWorld)--学习笔记
- .NET 云原生架构师训练营(ASP .NET Core 整体概念推演)--学习笔记
- .NET 云原生架构师训练营(模块二 基础巩固 引入)--学习笔记
- .NET 云原生架构师训练营(模块二 基础巩固 REST && RESTful)--学习笔记
- .NET 云原生架构师训练营(模块二 基础巩固 EF Core 介绍)--学习笔记
- .NET 云原生架构师训练营(模块二 基础巩固 MongoDB 更新和删除)--学习笔记
- .NET 云原生架构师训练营(模块二 基础巩固 MongoDB 聚合)--学习笔记
- .NET 云原生架构师训练营(模块二 基础巩固 RabbitMQ 业务场景详解)--学习笔记
- .NET 云原生架构师训练营(模块二 基础巩固 RabbitMQ 工作队列和交换机)--学习笔记
- .NET 云原生架构师训练营(模块二 基础巩固 MySQL环境准备)--学习笔记