如何使用應用程式秘密組態

秘密管理員工具,預設會在專案的開發期間儲存機密資料,絕對不要將密碼或其他敏感性資料儲存在原始程式碼中,機密資料不應與應用程式一起部署。應該透過像是環境變數或 Azure 金鑰保存庫等受控方式來存取生產秘密。 您可以透過 Azure Key Vault 設定提供者  儲存及保護 Azure 測試與生產祕密。

開發環境

  • Rider 2021.3.4
  • Windows 10
  • .Net Fx 4.8 via 新版專案範本 .NET Project SDKs
  • Microsoft.Extensions.Configuration 5.0.0
  • Microsoft.Extensions.Hosting 5.0.0
     

應用程式秘密組態

  • 儲存在專案樹狀結構中的不同位置
  • 會與特定專案建立關聯或在數個專案之間共用
  • 不會簽入原始檔控制中。
秘密管理員工具不會加密儲存的密碼,也不應將其視為受信任的存放區。這僅適用于開發用途,金鑰和值會儲存在使用者設定檔目錄的 JSON 設定檔中。

 

設定秘密

專案目錄中執行下列命令

命令查詢

dotnet user-secrets -h

啟用秘密儲存體

dotnet user-secrets init

專案組態會多一個UserSecretsId的節點

<UserSecretsId>659be13b-676e-4c9e-a0b9-0df2ffd75cfc</UserSecretsId>

設定秘密

設定目前專案資料夾的秘密組態

dotnet user-secrets set "Player:Key" "from secret config 12345"

設定其他專案資料夾的秘密組態

dotnet user-secrets set "Player:Key" "from secret config 12345" --project "C:\apps\WebApp1\src\WebApp1"
 

最終存成秘密檔案時會壓扁結構

{
  "Player:Key": "12345"
}

 

而不是像 josn 的檔案結構

{
    "ConnectionStrings": {
      "DefaultConnectionString": "Server=(localdb)\\mssqllocaldb;Database=ConsoleApp.NewDb;Trusted_Connection=True;"
    },
    "Player": {
      "AppId": "play1",
      "Key": "1234567890"
    }
  }
}

 

檔案的路徑會在

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

Linux/macOS:~/.microsoft/usersecrets/<user_secrets_id>/secrets.json
 

或是透過 VS IDE 開啟秘密檔案

 

移除秘密

dotnet user-secrets remove "Player:Key"

列出秘密

dotnet user-secrets list

移除所有秘密

dotnet user-secrets clear

讀取秘密

上篇,如何使用 .NET Generic Host for Microsoft.Extensions.Hosting | 余小章 @ 大內殿堂 - 點部落 (dotblogs.com.tw) 提到 Host.CreateDefaultBuilder 內部的行為已經幫我們載入秘密組態了

 

config.AddUserSecrets(appAssembly, optional: true);

Host.CreateDefaultBuilder 雖然會幫我們調用 IConfigurationBuilder.AddUserSecrets,在測試專案因條件不足

所以我要動一些手腳,修改 Host Configuration

[TestMethod]
public void 讀取秘密()
{
    var builder = Host.CreateDefaultBuilder()
                      .ConfigureHostConfiguration((config)=>
                                                  {
                                                      config.AddJsonFile("appsettings.json", false, true);
                                                  })
        ;  
    var host = builder.Build();

    var config = host.Services.GetService<IConfiguration>();
    Console.WriteLine($"Player:Key = {config["Player:Key"]}");
}

 

在 appsettings.json增加 Environment、ApplicationName 節點

{
  "ConnectionStrings": {
    "DefaultConnectionString": "Server=(localdb)\\mssqllocaldb;Database=EFGetStarted.ConsoleApp.NewDb;Trusted_Connection=True;"
  },
  "Player": {
    "AppId": "player1",
    "Key": "1234567890"
  },
  "Environment": "Development",
  "ApplicationName":"NetFx48"
}

 

執行結果可以讀取到秘密組態了

Player:Key = from secret config 12345

 

手動實例化組態並使用秘密

[TestMethod]
public void 手動實例化組態讀取秘密()
{
    var builder = new ConfigurationBuilder()
                  .SetBasePath(Directory.GetCurrentDirectory())
                  .AddJsonFile("appsettings.json")
                  .AddUserSecrets<SurveyUserSecretTests>()
        ;

    var config = builder.Build();
    Console.WriteLine($"Player:Key = {config["Player:Key"]}");
}

 

參考

在 ASP.NET Core 的開發中安全儲存應用程式秘密 | Microsoft Docs

範例位置

sample.dotblog/SurveyUserSecretTests.cs at master · yaochangyu/sample.dotblog (github.com)

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo