你好,這里是 Dotnet 工具箱,定期分享 Dotnet 有趣,實(shí)用的工具和組件,希望對(duì)您有用!
(資料圖)
DotNetCorePlugins 是一個(gè) .NET 的開源插件項(xiàng)目,它提供了能夠動(dòng)態(tài)加載程序集的 API,然后把它們作為 .NET 主程序的擴(kuò)展程序執(zhí)行。
這個(gè)庫主要用到了 AssemblyLoadContext
技術(shù), System.Runtime.Loader.AssemblyLoadContext
,又名 ALC,提供了一些用于定義動(dòng)態(tài)程序集加載行為的基本 API。這是 .NET Core 中我最喜歡但鮮為人知的 API 之一。
安裝 McMaster.NETCore.Plugins
NuGet 包。
dotnet add package McMaster.NETCore.Plugins
主要使用的 API 是 PluginLoader.CreateFromAssemblyFile
, 它允許從文件中讀取并加載程序集。
PluginLoader.CreateFromAssemblyFile( assemblyFile: "./plugins/MyPlugin/MyPlugin1.dll", sharedTypes: new [] { typeof(IPlugin), typeof(IServiceCollection), typeof(ILogger) }, isUnloadable: true)
assemblyFile = 插件 .dll 的文件路徑sharedTypes = 加載程序的統(tǒng)一的類型列表isUnloadable = 允許這個(gè)插件在將來的某個(gè)時(shí)候從內(nèi)存中卸載。定義接口
這是一個(gè)示例,我們定義了一個(gè)接口,里面包含了 GetName, 如下
public interface IPlugin{ string GetName();}
對(duì)于插件,我們直接使用這個(gè)接口并進(jìn)行實(shí)現(xiàn),如下
internal class MyPlugin1 : IPlugin{ public string GetName() => "My plugin v1";}
對(duì)于主程序,我們可以使用 PluginLoader
API 來加載插件,程序需要使用查找磁盤中的插件程序集。一種方式是基于約定的,比如
plugins/ $PluginName1/ $PluginName1.dll (additional plugin files) $PluginName2/ $PluginName2.dll
每個(gè)插件都發(fā)布到一個(gè)單獨(dú)的目錄中,這樣可以避免插件之間的爭用和重復(fù)的依賴問題。
以通過運(yùn)行下面的命令,輸出插件到文件夾中。
dotnet publish MyPlugin1.csproj --output plugins/MyPlugin1/
接下來,我們可以通過反射獲取所有的插件,并進(jìn)行加載, 代碼如下
using McMaster.NETCore.Plugins;var loaders = new List();// create plugin loadersvar pluginsDir = Path.Combine(AppContext.BaseDirectory, "plugins");foreach (var dir in Directory.GetDirectories(pluginsDir)){ var dirName = Path.GetFileName(dir); var pluginDll = Path.Combine(dir, dirName + ".dll"); if (File.Exists(pluginDll)) { var loader = PluginLoader.CreateFromAssemblyFile( pluginDll, sharedTypes: new [] { typeof(IPlugin) }); loaders.Add(loader); }}// Create an instance of plugin typesforeach (var loader in loaders){ foreach (var pluginType in loader .LoadDefaultAssembly() .GetTypes() .Where(t => typeof(IPlugin).IsAssignableFrom(t) && !t.IsAbstract)) { IPlugin plugin = (IPlugin)Activator.CreateInstance(pluginType); Console.WriteLine($"Created plugin instance "{plugin.GetName()}"."); }}
支持 MVC 和 Razor
另外插件還支持加載 MVC 的 Controller 和 Razor Pages。通過安裝下面的 Nuget 包。
dotnet add package McMaster.NETCore.Plugins.Mvc
加載程序集的方法如下:
public class Startup{ public void ConfigureServices(IServiceCollection services) { var pluginFile = Path.Combine(AppContext.BaseDirectory, "plugins/MyRazorPlugin/MyRazorPlugin.dll"); services .AddMvc() .AddPluginFromAssemblyFile(pluginFile); }}
更多插件的使用方法,作者提供了一些示例項(xiàng)目,可以進(jìn)行參考。
https://github.com/natemcmaster/DotNetCorePlugins
2. 推薦一個(gè)強(qiáng)大高效的開源 .NET 訪問控制組件Casbin 簡介Casbin 是一個(gè)強(qiáng)大高效的開源訪問控制庫,支持各種 訪問控制模型 , 如 ACL, RBAC, ABAC 等。
我們希望可以讓指定的主體 subject,可以訪問指定的資源 object,訪問可以是讀和寫。這就是 Casbin 使用最廣泛的方式。也稱為 { subject, object, action }
流程。
另外,Casbin 能夠處理標(biāo)準(zhǔn)流程以外的許多復(fù)雜授權(quán)場景,還支持添加 RBAC 和 ABAC 等。
Casbin 能做什么?{ subject, object, action } 定義訪問策略,支持允許和拒絕授權(quán)。處理訪問控制模型和策略的存儲(chǔ)。管理角色-用戶映射和角色-角色映射(也稱為 RBAC 中的角色層次結(jié)構(gòu))。支持內(nèi)置超級(jí)用戶,例如root
或administrator
。超級(jí)用戶可以在沒有明確許可的情況下做任何事情。內(nèi)置多種運(yùn)算符,支持規(guī)則匹配。例如,keyMatch
可以將資源鍵映射/foo/bar
到模式/foo*
。Casbin 不做的事用戶身份驗(yàn)證。管理用戶和角色列表。Casbin 支持的語言Casbin 提供對(duì)各種編程語言的支持,可以集成到任何項(xiàng)目和工作流程中:
它是怎么運(yùn)行的?在Casbin中,基于PERM元模型 (Policy, Effect, Request, Matchers)將一個(gè)訪問控制模型抽象成一個(gè)CONF文件。
所以切換或升級(jí)項(xiàng)目的授權(quán)機(jī)制就像修改配置一樣簡單。
Casbin中 最基本最簡單的模型就是ACL。ACL 的模型 CONF 是:
# Request definition[request_definition]r = sub, obj, act# Policy definition[policy_definition]p = sub, obj, act# Policy effect[policy_effect]e = some(where (p.eft == allow))# Matchers[matchers]m = r.sub == p.sub && r.obj == p.obj && r.act == p.act
ACL 模型的示例策略如下:
p, alice, data1, readp, bob, data2, write
它的意思是:
alice 可以讀取 data1.bob 可以寫入 data2。如何使用?首先,需要安裝 Casbin.NET。
dotnet add package Casbin.NET
使用模型文件和策略文件新建一個(gè) Casbin 執(zhí)行器:var e = new Enforcer("path/to/model.conf", "path/to/policy.csv")
注意:這里您還可以使用數(shù)據(jù)庫中的策略而不是文件來初始化執(zhí)行器。
在進(jìn)行資源訪問的時(shí)候,使用下面的授權(quán)代碼。var sub = "alice"; # 想要訪問資源的用戶var obj = "data1"; # 將要被訪問的資源var act = "read"; # 用戶對(duì)資源進(jìn)行的操作if (await e.EnforceAsync(sub, obj, act)) { // 允許alice讀取data1}else{ // 拒絕請(qǐng)求,拋出異常}
https://github.com/casbin/Casbin.NET
關(guān)鍵詞: