Blazor 在開發環境保存機密(User Secrets)

前言

在應用程序開發的過程中,有的時候需要在代碼中保存一些機密的信息,比如微信appkey, 連接字符串,加密密鑰,字符串,或者是用戶名密碼等。通常的做法是保存到一個配置文件中,例如 appsettings.json, 以之前文章”Blazor組件自做五: 使用JS隔離封裝Google地圖” 為例 ,其中有一段代碼

@inject IConfiguration config

[Parameter]
public string? Key { get; set; }

key = Key ?? config["GoogleKey"];

意思是在 IConfiguration 服務獲取 “GoogleKey” , 默認在 appsettings.json 文件配置. 問題就來了,如果我們在工程的 appsettings.json 文件明文保存 GoogleKey , 多人開發或者開源同步到Github/碼雲上,那肯定是極其不安全的.

嚴重建議勿在源代碼中存儲密碼或其他敏感數據。 也不要將生產機密用於開發或測試。 機密不隨應用一起部署。

用戶機密介紹

使用用戶機密的場景:

需要保存一些和第三方網站對接的密鑰,比如和 微信,微博站點使用的 appkey
給每個開發人員配置不用的用戶名密碼來訪問一些資源
開發人員在開發過程中使用各自本機的數據庫,如何配置數據庫地址、賬號和密碼
假設說最後一項,每個開發要使用自己本機的數據庫,你可能會說讓每個人修改自己的appsettings.config,在提交代碼的時候不提交就行了。那麼如果在appsettings.config添加其他配置項的時候,顯然不提交appsettings.config文件不合理的。

現在,ASP.NET Core 提供了一種很優雅簡潔的方式 User Secrets 用來幫助我們解決這個事情。

機密管理器

機密管理器工具存儲 ASP.NET Core 項目開發期間的敏感數據。 在此上下文中,一段敏感數據是應用機密。 應用機密存儲在與項目樹不同的位置。 應用機密與特定項目關聯,或者跨多個項目共享。 應用機密不會簽入到源代碼管理中。

機密管理器工具的工作原理

機密管理器工具會隱藏實現詳細信息,例如值的存儲位置和存儲方法。 可在不知道這些實現詳細信息的情況下使用該工具。 這些值存儲在本地計算機的用戶配置文件文件夾中的 JSON 文件中:

Windows文件系統路徑:

%APPDATA%\Microsoft\UserSecrets\<user_secrets_id>\secrets.json

Linux/macOS 文件系統路徑:

~/.microsoft/usersecrets/<user_secrets_id>/secrets.json

在上述文件路徑中,將 <user_secrets_id> 替換為在項目文件中指定的 UserSecretsId 值。

不要編寫依賴於使用機密管理器工具保存的數據的位置或格式的代碼。 這些實現詳細信息可能有變。 例如,機密值不會加密,但將來可能會加密。

啟用機密存儲

在 Visual Studio 2022 中,在解決方案資源管理器中右鍵單擊該項目,然後從上下文菜單中選擇「管理用戶機密」。

QQ截圖20220408020409

該操作會將 UserSecretsId 元素添加到項目文件的 PropertyGroup 中。 默認情況下,UserSecretsId 的內部文本是 GUID。 內部文本是任意的,但對於項目來說是唯一的。

<PropertyGroup>
  <UserSecretsId>79a3edd0-2092-40a2-a04d-dcb46d5ca9ed</UserSecretsId>
</PropertyGroup>

在應用程序中使用用戶機密

要在應用程序中訪問配置的用戶機密,你需要保證project.json文件中存在依賴項:

Microsoft.Extensions.Configuration.UserSecrets 並且builder.AddUserSecrets()。

然後在Startup.cs文件中通過 Configuration 對象訪問

var builder = WebApplication.CreateBuilder(args);
var movieApiKey = builder.Configuration["ApiKey"];

實際操作

1. 新建工程n01UserSecrets. 將項目添加到解決方案中

dotnet new blazorserver -o n01UserSecrets
dotnet sln add n01UserSecrets/n01UserSecrets.csproj

2. 在解決方案資源管理器中右鍵單擊n01UserSecrets項目,然後從上下文菜單中選擇「管理用戶機密」。

打開的文件內容替換為

{
   "ApiKey": "12345" 
}

3. Program.cs 文件使用

var movieApiKey = builder.Configuration["ApiKey"];
Console.WriteLine(movieApiKey);

QQ截圖20220408021506

4. Razor 頁面使用

Key is @apiKey

@code{
    [Inject] IConfiguration? config { get; set; }

    string? apiKey { get => config!["ApiKey"]; } 
}

QQ截圖20220408023411

5. 不同項目共享機密存儲文件

以控制台為例

dotnet new console -o n01UserSecretsConsole
dotnet sln add n01UserSecretsConsole/n01UserSecretsConsole.csproj

5.1. 在解決方案資源管理器中右鍵單擊n01UserSecretsConsole項目,然後從上下文菜單中選擇「管理用戶機密」。

5.2. 雙擊項目n01UserSecrets,打開項目配置,找到UserSecretsId一行,整行複製

<UserSecretsId>979b4b67-add4-46bb-80c6-49dab268ca91</UserSecretsId>

5.3. 在解決方案資源管理器中右鍵單擊n01UserSecretsConsole項目,然後從上下文菜單中選擇「管理用戶機密」。

5.4. 雙擊項目n01UserSecretsConsole,找到UserSecretsId一行,替換為複製的內容

<UserSecretsId>979b4b67-add4-46bb-80c6-49dab268ca91</UserSecretsId>

5.5. Program.cs 文件測試效果

using Microsoft.Extensions.Configuration;  
IConfiguration? Config;

Config = new ConfigurationBuilder().AddUserSecrets<Program>().Build();
var apiKey = Config["ApiKey"];
Console.WriteLine(apiKey);

QQ截圖20220408023007

.NET CLI

  • 啟用機密存儲
dotnet user-secrets init
  • 設置機密
dotnet user-secrets set "Movies:ServiceApiKey" "12345"

在上述示例中,冒號表示 Movies 是具有 ServiceApiKey 屬性的對象文字。

  • 列出機密
dotnet user-secrets list
  • 刪除單個機密
dotnet user-secrets remove "Movies:ConnectionString"
  • 刪除所有機密
dotnet user-secrets clear

優先級

注意:如果你的appsetting.json文件中有和secrets.json文件中相同節點(衝突)的配置項,那麼就會被secrets.json中的設置項給覆蓋掉,因為 builder.AddUserSecrets()晚於 AddJsonFile(“appsettings.json”)註冊, 那麼我們可以利用這個特性來在每個開發人員的機器上重新設置數據庫連接字符串了。

總結

以上,或許可以感受到微軟在 ASP.NET Core 中對於開發人員還是非常貼心的,很多小細節都考慮到了,因此在我們構建應用程序的過程中,可以多使用這些小功能(特性)來讓我們的代碼更加的優雅~

參考資料

項目源碼

Github | Gitee

關聯項目

FreeSql QQ群:4336577(已滿)、8578575(已滿)、52508226(在線)

BA & Blazor QQ群:795206915、675147445

知識共享許可協議

本作品採用 知識共享署名-非商業性使用-相同方式共享 4.0 國際許可協議 進行許可。歡迎轉載、使用、重新發佈,但務必保留文章署名AlexChow(包含鏈接: //github.com/densen2014 ),不得用於商業目的,基於本文修改後的作品務必以相同的許可發佈。如有任何疑問,請與我聯繫

AlexChow

今日頭條 | 博客園 | 知乎 | Gitee | GitHub