ASP.NET Core 中的开发中安全存储应用机密Safe storage of app secrets in development in ASP.NET Core

作者: Rick AndersonKirk LarkinDaniel RothScott AddieBy Rick Anderson, Kirk Larkin, Daniel Roth, and Scott Addie

查看或下载示例代码如何下载View or download sample code (how to download)

本文档介绍如何管理开发计算机上的 ASP.NET Core 应用程序的敏感数据。This document explains how to manage sensitive data for an ASP.NET Core app on a development machine. 切勿在源代码中存储密码或其他敏感数据。Never store passwords or other sensitive data in source code. 生产机密不应用于开发或测试。Production secrets shouldn't be used for development or test. 机密不应与应用一起部署。Secrets shouldn't be deployed with the app. 相反,应通过受控的方式(如环境变量或 Azure Key Vault)访问生产机密。Instead, production secrets should be accessed through a controlled means like environment variables or Azure Key Vault. 可使用 Azure Key Vault 配置提供程序存储和保护 Azure 测试和生产机密。You can store and protect Azure test and production secrets with the Azure Key Vault configuration provider.

环境变量Environment variables

环境变量用于避免在代码中或在本地配置文件中存储应用程序机密。Environment variables are used to avoid storage of app secrets in code or in local configuration files. 环境变量会重写所有以前指定的配置源的配置值。Environment variables override configuration values for all previously specified configuration sources.

请考虑一个 ASP.NET Core web 应用,其中启用了 单个用户帐户 安全。Consider an ASP.NET Core web app in which Individual User Accounts security is enabled. 带有密钥的项目文件中包含默认的数据库连接字符串 appsettings.json DefaultConnectionA default database connection string is included in the project's appsettings.json file with the key DefaultConnection. 默认连接字符串用于 LocalDB,后者在用户模式下运行,不需要密码。The default connection string is for LocalDB, which runs in user mode and doesn't require a password. 在应用程序部署过程中, DefaultConnection 可使用环境变量的值覆盖密钥值。During app deployment, the DefaultConnection key value can be overridden with an environment variable's value. 环境变量可以存储具有敏感凭据的完整连接字符串。The environment variable may store the complete connection string with sensitive credentials.

警告

环境变量通常以未加密的纯文本格式存储。Environment variables are generally stored in plain, unencrypted text. 如果计算机或进程受到危害,则不受信任方可以访问环境变量。If the machine or process is compromised, environment variables can be accessed by untrusted parties. 可能需要其他措施来防止泄露用户机密。Additional measures to prevent disclosure of user secrets may be required.

所有平台上的环境变量分层键都不支持 : 分隔符。The : separator doesn't work with environment variable hierarchical keys on all platforms. __(双下划线):__, the double underscore, is:

  • 受所有平台支持。Supported by all platforms. 例如,Bash 不支持 : 分隔符,但支持 __For example, the : separator is not supported by Bash, but __ is.
  • 自动替换为 :Automatically replaced by a :

机密管理器Secret Manager

机密管理器工具在开发 ASP.NET Core 项目的过程中存储敏感数据。The Secret Manager tool stores sensitive data during the development of an ASP.NET Core project. 在此上下文中,一段敏感数据是应用程序机密。In this context, a piece of sensitive data is an app secret. 应用密钥存储在与项目树不同的位置。App secrets are stored in a separate location from the project tree. 应用程序机密与特定项目关联或在多个项目之间共享。The app secrets are associated with a specific project or shared across several projects. 应用密码未签入源控件。The app secrets aren't checked into source control.

警告

机密管理器工具不会加密存储的机密,也不应将其视为受信任的存储区。The Secret Manager tool doesn't encrypt the stored secrets and shouldn't be treated as a trusted store. 它仅用于开发目的。It's for development purposes only. 密钥和值存储在用户配置文件目录中的 JSON 配置文件中。The keys and values are stored in a JSON configuration file in the user profile directory.

机密管理器工具的工作原理How the Secret Manager tool works

机密管理器工具隐藏了实现的详细信息,例如存储值的位置和方式。The Secret Manager tool hides implementation details, such as where and how the values are stored. 您可以使用该工具,而无需了解这些实现细节。You can use the tool without knowing these implementation details. 这些值存储在本地计算机的用户配置文件文件夹中的 JSON 文件中:The values are stored in a JSON file in the local machine's user profile folder:

文件系统路径:File system path:

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

在前面的文件路径中,将替换 <user_secrets_id>UserSecretsId 项目文件中指定的值。In the preceding file paths, replace <user_secrets_id> with the UserSecretsId value specified in the project file.

不要编写依赖于通过机密管理器工具保存的数据的位置或格式的代码。Don't write code that depends on the location or format of data saved with the Secret Manager tool. 这些实现细节可能会发生变化。These implementation details may change. 例如,机密值不会加密,但可能会在将来。For example, the secret values aren't encrypted, but could be in the future.

启用密钥存储Enable secret storage

机密管理器工具对存储在用户配置文件中的特定于项目的配置设置进行操作。The Secret Manager tool operates on project-specific configuration settings stored in your user profile.

机密管理器工具 init 在 .NET Core SDK 3.0.100 或更高版本中包含命令。The Secret Manager tool includes an init command in .NET Core SDK 3.0.100 or later. 若要使用用户机密,请在项目目录中运行以下命令:To use user secrets, run the following command in the project directory:

dotnet user-secrets init

前面的命令将在 UserSecretsId 项目文件的中添加一个元素 PropertyGroupThe preceding command adds a UserSecretsId element within a PropertyGroup of the project file. 默认情况下,的内部文本 UserSecretsId 是 GUID。By default, the inner text of UserSecretsId is a GUID. 内部文本是任意的,但对项目是唯一的。The inner text is arbitrary, but is unique to the project.

<PropertyGroup>
  <TargetFramework>netcoreapp3.1</TargetFramework>
  <UserSecretsId>79a3edd0-2092-40a2-a04d-dcb46d5ca9ed</UserSecretsId>
</PropertyGroup>

在 Visual Studio 中,右键单击 "解决方案资源管理器中的项目,然后从上下文菜单中选择" 管理用户机密 "。In Visual Studio, right-click the project in Solution Explorer, and select Manage User Secrets from the context menu. 此笔势将 UserSecretsId 使用 GUID 填充的元素添加到项目文件。This gesture adds a UserSecretsId element, populated with a GUID, to the project file.

设置机密Set a secret

定义包含密钥及其值的应用密码。Define an app secret consisting of a key and its value. 机密与项目的值相关联 UserSecretsIdThe secret is associated with the project's UserSecretsId value. 例如,从项目文件所在的目录运行以下命令:For example, run the following command from the directory in which the project file exists:

dotnet user-secrets set "Movies:ServiceApiKey" "12345"

在前面的示例中,冒号表示 Movies 是具有属性的对象文本 ServiceApiKeyIn the preceding example, the colon denotes that Movies is an object literal with a ServiceApiKey property.

机密管理器工具也可用于其他目录。The Secret Manager tool can be used from other directories too. 使用 --project 选项可提供项目文件所在的文件系统路径。Use the --project option to supply the file system path at which the project file exists. 例如:For example:

dotnet user-secrets set "Movies:ServiceApiKey" "12345" --project "C:\apps\WebApp1\src\WebApp1"

Visual Studio 中的 JSON 结构平展JSON structure flattening in Visual Studio

Visual Studio 的 " 管理用户机密 " 手势在文本编辑器中打开文件的 secrets.jsVisual Studio's Manage User Secrets gesture opens a secrets.json file in the text editor. 上secrets.js 的内容替换为要存储的键值对。Replace the contents of secrets.json with the key-value pairs to be stored. 例如:For example:

{
  "Movies": {
    "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
    "ServiceApiKey": "12345"
  }
}

JSON 结构是通过或进行修改后平展的 dotnet user-secrets remove dotnet user-secrets setThe JSON structure is flattened after modifications via dotnet user-secrets remove or dotnet user-secrets set. 例如,运行会 dotnet user-secrets remove "Movies:ConnectionString" 折叠 Movies 对象文本。For example, running dotnet user-secrets remove "Movies:ConnectionString" collapses the Movies object literal. 修改后的文件类似于以下 JSON:The modified file resembles the following JSON:

{
  "Movies:ServiceApiKey": "12345"
}

设置多个机密Set multiple secrets

可以通过管道 JSON 将密码批设置为 set 命令。A batch of secrets can be set by piping JSON to the set command. 在下面的示例中,将文件的内容的 input.js 传递给 set 命令。In the following example, the input.json file's contents are piped to the set command.

打开命令 shell,然后执行以下命令:Open a command shell, and execute the following command:

type .\input.json | dotnet user-secrets set

访问机密Access a secret

若要访问密钥,请完成以下步骤:To access a secret, complete the following steps:

  1. 注册用户机密配置源Register the user secrets configuration source
  2. 通过配置 API 读取机密Read the secret via the Configuration API

注册用户机密配置源Register the user secrets configuration source

用户机密 配置提供程序 向 .NET 配置 API注册适当的配置源。The user secrets configuration provider registers the appropriate configuration source with the .NET Configuration API.

当项目调用时,用户机密配置源会自动以开发模式添加 CreateDefaultBuilderThe user secrets configuration source is automatically added in Development mode when the project calls CreateDefaultBuilder. CreateDefaultBuilderAddUserSecrets当为时 EnvironmentName 调用 DevelopmentCreateDefaultBuilder calls AddUserSecrets when the EnvironmentName is Development:

public static IHostBuilder CreateHostBuilder(string[] args) =>
    Host.CreateDefaultBuilder(args)
        .ConfigureWebHostDefaults(webBuilder =>
        {
            webBuilder.UseStartup<Startup>();
        });

如果 CreateDefaultBuilder 未调用,则通过在中调用来显式添加用户机密配置源 AddUserSecrets ConfigureAppConfigurationWhen CreateDefaultBuilder isn't called, add the user secrets configuration source explicitly by calling AddUserSecrets in ConfigureAppConfiguration. AddUserSecrets仅在开发环境中运行应用时调用,如以下示例中所示:Call AddUserSecrets only when the app runs in the Development environment, as shown in the following example:

public class Program
{
    public static void Main(string[] args)
    {
        var host = new HostBuilder()
            .ConfigureAppConfiguration((hostContext, builder) =>
            {
                // Add other providers for JSON, etc.

                if (hostContext.HostingEnvironment.IsDevelopment())
                {
                    builder.AddUserSecrets<Program>();
                }
            })
            .Build();
        
        host.Run();
    }
}

通过配置 API 读取机密Read the secret via the Configuration API

如果注册了用户机密配置源,则 .NET 配置 API 可以读取机密。If the user secrets configuration source is registered, the .NET Configuration API can read the secrets. 构造函数注入 可用于获取对 .NET 配置 API 的访问。Constructor injection can be used to gain access to the .NET Configuration API. 请考虑以下读取密钥的示例 Movies:ServiceApiKeyConsider the following examples of reading the Movies:ServiceApiKey key:

Startup 类:Startup class:

public class Startup
{
    private string _moviesApiKey = null;

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        _moviesApiKey = Configuration["Movies:ServiceApiKey"];
    }

    public void Configure(IApplicationBuilder app)
    {
        app.Run(async (context) =>
        {
            var result = string.IsNullOrEmpty(_moviesApiKey) ? "Null" : "Not Null";
            await context.Response.WriteAsync($"Secret is {result}");
        });
    }
}

Razor 页面页面模型:Razor Pages page model:

public class IndexModel : PageModel
{
    private readonly IConfiguration _config;

    public IndexModel(IConfiguration config)
    {
        _config = config;
    }

    public void OnGet()
    {
        var moviesApiKey = _config["Movies:ServiceApiKey"];

        // call Movies service with the API key
    }
}

有关详细信息,请参阅 " 在启动访问配置" Razor 页中的访问配置。For more information, see Access configuration in Startup and Access configuration in Razor Pages.

将机密映射到 POCOMap secrets to a POCO

将整个对象文本映射到 POCO (具有属性) 的简单 .NET 类对于聚合相关属性十分有用。Mapping an entire object literal to a POCO (a simple .NET class with properties) is useful for aggregating related properties.

假设文件上的应用 secrets.js 包含以下两个机密:Assume the app's secrets.json file contains the following two secrets:

{
  "Movies": {
    "ServiceApiKey": "12345",
    "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

若要将上述机密映射到 POCO,请使用 .NET 配置 API 的 对象图绑定 功能。To map the preceding secrets to a POCO, use the .NET Configuration API's object graph binding feature. 下面的代码绑定到自定义 MovieSettings POCO 并访问 ServiceApiKey 属性值:The following code binds to a custom MovieSettings POCO and accesses the ServiceApiKey property value:

var moviesConfig = 
    Configuration.GetSection("Movies").Get<MovieSettings>();
_moviesApiKey = moviesConfig.ServiceApiKey;

Movies:ConnectionStringMovies:ServiceApiKey 机密映射到中的相应属性 MovieSettingsThe Movies:ConnectionString and Movies:ServiceApiKey secrets are mapped to the respective properties in MovieSettings:

public class MovieSettings
{
    public string ConnectionString { get; set; }

    public string ServiceApiKey { get; set; }
}

用机密替换字符串String replacement with secrets

以纯文本形式存储密码是不安全的。Storing passwords in plain text is insecure. 例如,存储在中的数据库连接字符串 appsettings.json 可能包含指定用户的密码:For example, a database connection string stored in appsettings.json may include a password for the specified user:

{
  "ConnectionStrings": {
    "Movies": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;User Id=johndoe;Password=pass123;MultipleActiveResultSets=true"
  }
}

更安全的方法是将密码存储为机密。A more secure approach is to store the password as a secret. 例如:For example:

dotnet user-secrets set "DbPassword" "pass123"

Password从中的连接字符串中移除键值对 appsettings.jsonRemove the Password key-value pair from the connection string in appsettings.json. 例如:For example:

{
  "ConnectionStrings": {
    "Movies": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;User Id=johndoe;MultipleActiveResultSets=true"
  }
}

可以对对象的属性设置机密的值 SqlConnectionStringBuilder Password ,以完成连接字符串:The secret's value can be set on a SqlConnectionStringBuilder object's Password property to complete the connection string:

public class Startup
{
    private string _connection = null;

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        var builder = new SqlConnectionStringBuilder(
            Configuration.GetConnectionString("Movies"));
        builder.Password = Configuration["DbPassword"];
        _connection = builder.ConnectionString;

        // code omitted for brevity
    }

    public void Configure(IApplicationBuilder app)
    {
        app.Run(async (context) =>
        {
            await context.Response.WriteAsync($"DB Connection: {_connection}");
        });
    }
}

列出机密List the secrets

假设文件上的应用 secrets.js 包含以下两个机密:Assume the app's secrets.json file contains the following two secrets:

{
  "Movies": {
    "ServiceApiKey": "12345",
    "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

从项目文件所在的目录运行以下命令:Run the following command from the directory in which the project file exists:

dotnet user-secrets list

随即显示以下输出:The following output appears:

Movies:ConnectionString = Server=(localdb)\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true
Movies:ServiceApiKey = 12345

在前面的示例中,键名称中的冒号表示 secrets.js上 的中的对象层次结构。In the preceding example, a colon in the key names denotes the object hierarchy within secrets.json.

删除单个机密Remove a single secret

假设文件上的应用 secrets.js 包含以下两个机密:Assume the app's secrets.json file contains the following two secrets:

{
  "Movies": {
    "ServiceApiKey": "12345",
    "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

从项目文件所在的目录运行以下命令:Run the following command from the directory in which the project file exists:

dotnet user-secrets remove "Movies:ConnectionString"

已修改文件 应用的secrets.js,以删除与密钥关联的键值对 MoviesConnectionStringThe app's secrets.json file was modified to remove the key-value pair associated with the MoviesConnectionString key:

{
  "Movies": {
    "ServiceApiKey": "12345"
  }
}

dotnet user-secrets list 显示以下消息:dotnet user-secrets list displays the following message:

Movies:ServiceApiKey = 12345

删除所有机密Remove all secrets

假设文件上的应用 secrets.js 包含以下两个机密:Assume the app's secrets.json file contains the following two secrets:

{
  "Movies": {
    "ServiceApiKey": "12345",
    "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

从项目文件所在的目录运行以下命令:Run the following command from the directory in which the project file exists:

dotnet user-secrets clear

此应用的所有用户机密已从文件中的 secrets.js 删除:All user secrets for the app have been deleted from the secrets.json file:

{}

运行 dotnet user-secrets list 将显示以下消息:Running dotnet user-secrets list displays the following message:

No secrets configured for this application.

其他资源Additional resources

作者: Rick AndersonDaniel RothScott AddieBy Rick Anderson, Daniel Roth, and Scott Addie

查看或下载示例代码如何下载View or download sample code (how to download)

本文档介绍如何管理开发计算机上的 ASP.NET Core 应用程序的敏感数据。This document explains how to manage sensitive data for an ASP.NET Core app on a development machine. 切勿在源代码中存储密码或其他敏感数据。Never store passwords or other sensitive data in source code. 生产机密不应用于开发或测试。Production secrets shouldn't be used for development or test. 机密不应与应用一起部署。Secrets shouldn't be deployed with the app. 相反,应通过受控的方式(如环境变量或 Azure Key Vault)访问生产机密。Instead, production secrets should be accessed through a controlled means like environment variables or Azure Key Vault. 可使用 Azure Key Vault 配置提供程序存储和保护 Azure 测试和生产机密。You can store and protect Azure test and production secrets with the Azure Key Vault configuration provider.

环境变量Environment variables

环境变量用于避免在代码中或在本地配置文件中存储应用程序机密。Environment variables are used to avoid storage of app secrets in code or in local configuration files. 环境变量会重写所有以前指定的配置源的配置值。Environment variables override configuration values for all previously specified configuration sources.

请考虑一个 ASP.NET Core web 应用,其中启用了 单个用户帐户 安全。Consider an ASP.NET Core web app in which Individual User Accounts security is enabled. 带有密钥的项目文件中包含默认的数据库连接字符串 appsettings.json DefaultConnectionA default database connection string is included in the project's appsettings.json file with the key DefaultConnection. 默认连接字符串用于 LocalDB,后者在用户模式下运行,不需要密码。The default connection string is for LocalDB, which runs in user mode and doesn't require a password. 在应用程序部署过程中, DefaultConnection 可使用环境变量的值覆盖密钥值。During app deployment, the DefaultConnection key value can be overridden with an environment variable's value. 环境变量可以存储具有敏感凭据的完整连接字符串。The environment variable may store the complete connection string with sensitive credentials.

警告

环境变量通常以未加密的纯文本格式存储。Environment variables are generally stored in plain, unencrypted text. 如果计算机或进程受到危害,则不受信任方可以访问环境变量。If the machine or process is compromised, environment variables can be accessed by untrusted parties. 可能需要其他措施来防止泄露用户机密。Additional measures to prevent disclosure of user secrets may be required.

所有平台上的环境变量分层键都不支持 : 分隔符。The : separator doesn't work with environment variable hierarchical keys on all platforms. __(双下划线):__, the double underscore, is:

  • 受所有平台支持。Supported by all platforms. 例如,Bash 不支持 : 分隔符,但支持 __For example, the : separator is not supported by Bash, but __ is.
  • 自动替换为 :Automatically replaced by a :

机密管理器Secret Manager

机密管理器工具在开发 ASP.NET Core 项目的过程中存储敏感数据。The Secret Manager tool stores sensitive data during the development of an ASP.NET Core project. 在此上下文中,一段敏感数据是应用程序机密。In this context, a piece of sensitive data is an app secret. 应用密钥存储在与项目树不同的位置。App secrets are stored in a separate location from the project tree. 应用程序机密与特定项目关联或在多个项目之间共享。The app secrets are associated with a specific project or shared across several projects. 应用密码未签入源控件。The app secrets aren't checked into source control.

警告

机密管理器工具不会加密存储的机密,也不应将其视为受信任的存储区。The Secret Manager tool doesn't encrypt the stored secrets and shouldn't be treated as a trusted store. 它仅用于开发目的。It's for development purposes only. 密钥和值存储在用户配置文件目录中的 JSON 配置文件中。The keys and values are stored in a JSON configuration file in the user profile directory.

机密管理器工具的工作原理How the Secret Manager tool works

机密管理器工具隐藏了实现的详细信息,例如存储值的位置和方式。The Secret Manager tool hides implementation details, such as where and how the values are stored. 您可以使用该工具,而无需了解这些实现细节。You can use the tool without knowing these implementation details. 这些值存储在本地计算机的用户配置文件文件夹中的 JSON 文件中:The values are stored in a JSON file in the local machine's user profile folder:

文件系统路径:File system path:

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

在前面的文件路径中,将替换 <user_secrets_id>UserSecretsId 项目文件中指定的值。In the preceding file paths, replace <user_secrets_id> with the UserSecretsId value specified in the project file.

不要编写依赖于通过机密管理器工具保存的数据的位置或格式的代码。Don't write code that depends on the location or format of data saved with the Secret Manager tool. 这些实现细节可能会发生变化。These implementation details may change. 例如,机密值不会加密,但可能会在将来。For example, the secret values aren't encrypted, but could be in the future.

启用密钥存储Enable secret storage

机密管理器工具对存储在用户配置文件中的特定于项目的配置设置进行操作。The Secret Manager tool operates on project-specific configuration settings stored in your user profile.

若要使用用户机密,请在 UserSecretsId 项目文件的中定义一个元素 PropertyGroupTo use user secrets, define a UserSecretsId element within a PropertyGroup of the project file. 的内部文本 UserSecretsId 是任意的,但对项目是唯一的。The inner text of UserSecretsId is arbitrary, but is unique to the project. 开发人员通常会生成的 GUID UserSecretsIdDevelopers typically generate a GUID for the UserSecretsId.

<PropertyGroup>
  <TargetFramework>netcoreapp2.1</TargetFramework>
  <UserSecretsId>79a3edd0-2092-40a2-a04d-dcb46d5ca9ed</UserSecretsId>
</PropertyGroup>

提示

在 Visual Studio 中,右键单击 "解决方案资源管理器中的项目,然后从上下文菜单中选择" 管理用户机密 "。In Visual Studio, right-click the project in Solution Explorer, and select Manage User Secrets from the context menu. 此笔势将 UserSecretsId 使用 GUID 填充的元素添加到项目文件。This gesture adds a UserSecretsId element, populated with a GUID, to the project file.

设置机密Set a secret

定义包含密钥及其值的应用密码。Define an app secret consisting of a key and its value. 机密与项目的值相关联 UserSecretsIdThe secret is associated with the project's UserSecretsId value. 例如,从项目文件所在的目录运行以下命令:For example, run the following command from the directory in which the project file exists:

dotnet user-secrets set "Movies:ServiceApiKey" "12345"

在前面的示例中,冒号表示 Movies 是具有属性的对象文本 ServiceApiKeyIn the preceding example, the colon denotes that Movies is an object literal with a ServiceApiKey property.

机密管理器工具也可用于其他目录。The Secret Manager tool can be used from other directories too. 使用 --project 选项可提供项目文件所在的文件系统路径。Use the --project option to supply the file system path at which the project file exists. 例如:For example:

dotnet user-secrets set "Movies:ServiceApiKey" "12345" --project "C:\apps\WebApp1\src\WebApp1"

Visual Studio 中的 JSON 结构平展JSON structure flattening in Visual Studio

Visual Studio 的 " 管理用户机密 " 手势在文本编辑器中打开文件的 secrets.jsVisual Studio's Manage User Secrets gesture opens a secrets.json file in the text editor. 上secrets.js 的内容替换为要存储的键值对。Replace the contents of secrets.json with the key-value pairs to be stored. 例如:For example:

{
  "Movies": {
    "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true",
    "ServiceApiKey": "12345"
  }
}

JSON 结构是通过或进行修改后平展的 dotnet user-secrets remove dotnet user-secrets setThe JSON structure is flattened after modifications via dotnet user-secrets remove or dotnet user-secrets set. 例如,运行会 dotnet user-secrets remove "Movies:ConnectionString" 折叠 Movies 对象文本。For example, running dotnet user-secrets remove "Movies:ConnectionString" collapses the Movies object literal. 修改后的文件类似于以下 JSON:The modified file resembles the following JSON:

{
  "Movies:ServiceApiKey": "12345"
}

设置多个机密Set multiple secrets

可以通过管道 JSON 将密码批设置为 set 命令。A batch of secrets can be set by piping JSON to the set command. 在下面的示例中,将文件的内容的 input.js 传递给 set 命令。In the following example, the input.json file's contents are piped to the set command.

打开命令 shell,然后执行以下命令:Open a command shell, and execute the following command:

type .\input.json | dotnet user-secrets set

访问机密Access a secret

配置 API提供对用户机密的访问权限。The Configuration API provides access to user secrets.

如果项目以 .NET Framework 为目标,请安装 Microsoft.Extensions.Configu。UserSecrets NuGet 包。If your project targets .NET Framework, install the Microsoft.Extensions.Configuration.UserSecrets NuGet package.

在 ASP.NET Core 2.0 或更高版本中,当项目调用时,用户机密配置源会自动以开发模式添加 CreateDefaultBuilderIn ASP.NET Core 2.0 or later, the user secrets configuration source is automatically added in development mode when the project calls CreateDefaultBuilder. CreateDefaultBuilderAddUserSecrets当为时 EnvironmentName 调用 DevelopmentCreateDefaultBuilder calls AddUserSecrets when the EnvironmentName is Development:

public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
    WebHost.CreateDefaultBuilder(args)
        .UseStartup<Startup>();

CreateDefaultBuilder不调用时,通过 AddUserSecrets 在构造函数中调用来显式添加用户机密配置源 StartupWhen CreateDefaultBuilder isn't called, add the user secrets configuration source explicitly by calling AddUserSecrets in the Startup constructor. AddUserSecrets仅在开发环境中运行应用时调用,如以下示例中所示:Call AddUserSecrets only when the app runs in the Development environment, as shown in the following example:

public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(env.ContentRootPath)
        .AddJsonFile("appsettings.json", 
                     optional: false, 
                     reloadOnChange: true)
        .AddEnvironmentVariables();

    if (env.IsDevelopment())
    {
        builder.AddUserSecrets<Startup>();
    }

    Configuration = builder.Build();
}

可以通过 .NET 配置 API 检索用户机密:User secrets can be retrieved via the .NET Configuration API:

public class Startup
{
    private string _moviesApiKey = null;

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        _moviesApiKey = Configuration["Movies:ServiceApiKey"];
    }

    public void Configure(IApplicationBuilder app)
    {
        app.Run(async (context) =>
        {
            var result = string.IsNullOrEmpty(_moviesApiKey) ? "Null" : "Not Null";
            await context.Response.WriteAsync($"Secret is {result}");
        });
    }
}

将机密映射到 POCOMap secrets to a POCO

将整个对象文本映射到 POCO (具有属性) 的简单 .NET 类对于聚合相关属性十分有用。Mapping an entire object literal to a POCO (a simple .NET class with properties) is useful for aggregating related properties.

假设文件上的应用 secrets.js 包含以下两个机密:Assume the app's secrets.json file contains the following two secrets:

{
  "Movies": {
    "ServiceApiKey": "12345",
    "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

若要将上述机密映射到 POCO,请使用 .NET 配置 API 的 对象图绑定 功能。To map the preceding secrets to a POCO, use the .NET Configuration API's object graph binding feature. 下面的代码绑定到自定义 MovieSettings POCO 并访问 ServiceApiKey 属性值:The following code binds to a custom MovieSettings POCO and accesses the ServiceApiKey property value:

var moviesConfig = Configuration.GetSection("Movies")
                                .Get<MovieSettings>();
_moviesApiKey = moviesConfig.ServiceApiKey;

Movies:ConnectionStringMovies:ServiceApiKey 机密映射到中的相应属性 MovieSettingsThe Movies:ConnectionString and Movies:ServiceApiKey secrets are mapped to the respective properties in MovieSettings:

public class MovieSettings
{
    public string ConnectionString { get; set; }

    public string ServiceApiKey { get; set; }
}

用机密替换字符串String replacement with secrets

以纯文本形式存储密码是不安全的。Storing passwords in plain text is insecure. 例如,存储在中的数据库连接字符串 appsettings.json 可能包含指定用户的密码:For example, a database connection string stored in appsettings.json may include a password for the specified user:

{
  "ConnectionStrings": {
    "Movies": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;User Id=johndoe;Password=pass123;MultipleActiveResultSets=true"
  }
}

更安全的方法是将密码存储为机密。A more secure approach is to store the password as a secret. 例如:For example:

dotnet user-secrets set "DbPassword" "pass123"

Password从中的连接字符串中移除键值对 appsettings.jsonRemove the Password key-value pair from the connection string in appsettings.json. 例如:For example:

{
  "ConnectionStrings": {
    "Movies": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;User Id=johndoe;MultipleActiveResultSets=true"
  }
}

可以对对象的属性设置机密的值 SqlConnectionStringBuilder Password ,以完成连接字符串:The secret's value can be set on a SqlConnectionStringBuilder object's Password property to complete the connection string:

public class Startup
{
    private string _connection = null;

    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {
        var builder = new SqlConnectionStringBuilder(
            Configuration.GetConnectionString("Movies"));
        builder.Password = Configuration["DbPassword"];
        _connection = builder.ConnectionString;
    }

    public void Configure(IApplicationBuilder app)
    {
        app.Run(async (context) =>
        {
            await context.Response.WriteAsync($"DB Connection: {_connection}");
        });
    }
}

列出机密List the secrets

假设文件上的应用 secrets.js 包含以下两个机密:Assume the app's secrets.json file contains the following two secrets:

{
  "Movies": {
    "ServiceApiKey": "12345",
    "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

从项目文件所在的目录运行以下命令:Run the following command from the directory in which the project file exists:

dotnet user-secrets list

随即显示以下输出:The following output appears:

Movies:ConnectionString = Server=(localdb)\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true
Movies:ServiceApiKey = 12345

在前面的示例中,键名称中的冒号表示 secrets.js上 的中的对象层次结构。In the preceding example, a colon in the key names denotes the object hierarchy within secrets.json.

删除单个机密Remove a single secret

假设文件上的应用 secrets.js 包含以下两个机密:Assume the app's secrets.json file contains the following two secrets:

{
  "Movies": {
    "ServiceApiKey": "12345",
    "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

从项目文件所在的目录运行以下命令:Run the following command from the directory in which the project file exists:

dotnet user-secrets remove "Movies:ConnectionString"

已修改文件 应用的secrets.js,以删除与密钥关联的键值对 MoviesConnectionStringThe app's secrets.json file was modified to remove the key-value pair associated with the MoviesConnectionString key:

{
  "Movies": {
    "ServiceApiKey": "12345"
  }
}

运行 dotnet user-secrets list 将显示以下消息:Running dotnet user-secrets list displays the following message:

Movies:ServiceApiKey = 12345

删除所有机密Remove all secrets

假设文件上的应用 secrets.js 包含以下两个机密:Assume the app's secrets.json file contains the following two secrets:

{
  "Movies": {
    "ServiceApiKey": "12345",
    "ConnectionString": "Server=(localdb)\\mssqllocaldb;Database=Movie-1;Trusted_Connection=True;MultipleActiveResultSets=true"
  }
}

从项目文件所在的目录运行以下命令:Run the following command from the directory in which the project file exists:

dotnet user-secrets clear

此应用的所有用户机密已从文件中的 secrets.js 删除:All user secrets for the app have been deleted from the secrets.json file:

{}

运行 dotnet user-secrets list 将显示以下消息:Running dotnet user-secrets list displays the following message:

No secrets configured for this application.

其他资源Additional resources