.NET 雲原生架構師訓練營(許可權系統 程式碼實現 EntityAccess)–學習筆記
- 2022 年 2 月 16 日
- 筆記
- 【006】.NET 雲原生架構師訓練營
目錄
- 開發任務
- 程式碼實現
開發任務
- 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源碼鏈接:
//github.com/MingsonZheng/dotnetnb.security
課程鏈接
//appsqsyiqlk5791.h5.xiaoeknow.com/v1/course/video/v_5f39bdb8e4b01187873136cf?type=2
本作品採用知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議進行許可。
歡迎轉載、使用、重新發布,但務必保留文章署名 鄭子銘 (包含鏈接: //www.cnblogs.com/MingsonZheng/ ),不得用於商業目的,基於本文修改後的作品務必以相同的許可發布。
如有任何疑問,請與我聯繫 ([email protected]) 。