【Dotnet 工具箱】DotNetCorePlugins- 動態載入和解除安裝 .NET 程式外掛

Dotnet工具箱發表於2023-05-08

你好,這裡是 Dotnet 工具箱,定期分享 Dotnet 有趣,實用的工具和元件,希望對您有用!

1. DotNetCorePlugins- 動態載入和解除安裝 .NET 程式外掛

DotNetCorePlugins 是一個 .NET 的開源外掛專案,它提供了能夠動態載入程式集的 API,然後把它們作為 .NET 主程式的擴充套件程式執行。

這個庫主要用到了 AssemblyLoadContext 技術, System.Runtime.Loader.AssemblyLoadContext,又名 ALC,提供了一些用於定義動態程式集載入行為的基本 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 = 載入程式的統一的型別列表
  • isUnloadable = 允許這個外掛在將來的某個時候從記憶體中解除安裝。

定義介面

這是一個示例,我們定義了一個介面,裡面包含了 GetName, 如下

public interface IPlugin
{
    string GetName();
}

對於外掛,我們直接使用這個介面並進行實現,如下

internal class MyPlugin1 : IPlugin
{
    public string GetName() => "My plugin v1";
}

對於主程式,我們可以使用 PluginLoader API 來載入外掛,程式需要使用查詢磁碟中的外掛程式集。一種方式是基於約定的,比如

plugins/
    $PluginName1/
        $PluginName1.dll
        (additional plugin files)
    $PluginName2/
        $PluginName2.dll

每個外掛都發布到一個單獨的目錄中,這樣可以避免外掛之間的爭用和重複的依賴問題。

以透過執行下面的命令,輸出外掛到資料夾中。

dotnet publish MyPlugin1.csproj --output plugins/MyPlugin1/

接下來,我們可以透過反射獲取所有的外掛,並進行載入, 程式碼如下

using McMaster.NETCore.Plugins;

var loaders = new List<PluginLoader>();

// create plugin loaders
var 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 types
foreach (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);
    }
}

更多外掛的使用方法,作者提供了一些示例專案,可以進行參考。

https://github.com/natemcmaster/DotNetCorePlugins

2. 推薦一個強大高效的開源 .NET 訪問控制元件

Casbin 簡介

Casbin 是一個強大高效的開源訪問控制庫,支援各種 訪問控制模型 , 如 ACL, RBAC, ABAC 等。

我們希望可以讓指定的主體 subject,可以訪問指定的資源 object,訪問可以是讀和寫。這就是 Casbin 使用最廣泛的方式。也稱為 { subject, object, action } 流程。

另外,Casbin 能夠處理標準流程以外的許多複雜授權場景,還支援新增 RBAC 和 ABAC 等。

Casbin 能做什麼?

  1. { subject, object, action } 定義訪問策略,支援允許和拒絕授權。
  2. 處理訪問控制模型和策略的儲存。
  3. 管理角色-使用者對映和角色-角色對映(也稱為 RBAC 中的角色層次結構)。
  4. 支援內建超級使用者,例如rootadministrator。超級使用者可以在沒有明確許可的情況下做任何事情。
  5. 內建多種運算子,支援規則匹配。例如,keyMatch可以將資源鍵對映/foo/bar到模式/foo*

Casbin 不做的事

  1. 使用者身份驗證。
  2. 管理使用者和角色列表。

Casbin 支援的語言

Casbin 提供對各種程式語言的支援,可以整合到任何專案和工作流程中:

它是怎麼執行的?

在Casbin中,基於PERM元模型 (Policy, Effect, Request, Matchers)將一個訪問控制模型抽象成一個CONF檔案。

所以切換或升級專案的授權機制就像修改配置一樣簡單。

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, read
p, bob, data2, write

它的意思是:

  • alice 可以讀取 data1.
  • bob 可以寫入 data2。

如何使用?

首先,需要安裝 Casbin.NET。

dotnet add package Casbin.NET
  1. 使用模型檔案和策略檔案新建一個 Casbin 執行器:
   var e = new Enforcer("path/to/model.conf", "path/to/policy.csv")

注意:這裡您還可以使用資料庫中的策略而不是檔案來初始化執行器。

  1. 在進行資源訪問的時候,使用下面的授權程式碼。
var sub = "alice";  # 想要訪問資源的使用者
var obj = "data1";  # 將要被訪問的資源
var act = "read";  # 使用者對資源進行的操作

if (await e.EnforceAsync(sub, obj, act)) 
{
    // 允許alice讀取data1
}
else
{
    // 拒絕請求,丟擲異常
}

https://github.com/casbin/Casbin.NET

相關文章