Blazor 在开发环境保存机密(User Secrets) - densen2014/Blazor100 GitHub Wiki
在应用程序开发的过程中,有的时候需要在代码中保存一些机密的信息,比如微信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 中,在解决方案资源管理器中右键单击该项目,然后从上下文菜单中选择“管理用户机密”。
该操作会将 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"];
dotnet new blazorserver -o n01UserSecrets
dotnet sln add n01UserSecrets/n01UserSecrets.csproj
打开的文件内容替换为
{
"ApiKey": "12345"
}
var movieApiKey = builder.Configuration["ApiKey"];
Console.WriteLine(movieApiKey);
Key is @apiKey
@code{
[Inject] IConfiguration? config { get; set; }
string? apiKey { get => config!["ApiKey"]; }
}
以控制台为例
dotnet new console -o n01UserSecretsConsole
dotnet sln add n01UserSecretsConsole/n01UserSecretsConsole.csproj
<UserSecretsId>979b4b67-add4-46bb-80c6-49dab268ca91</UserSecretsId>
<UserSecretsId>979b4b67-add4-46bb-80c6-49dab268ca91</UserSecretsId>
using Microsoft.Extensions.Configuration;
IConfiguration? Config;
Config = new ConfigurationBuilder().AddUserSecrets<Program>().Build();
var apiKey = Config["ApiKey"];
Console.WriteLine(apiKey);
- 启用机密存储
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 中对于开发人员还是非常贴心的,很多小细节都考虑到了,因此在我们构建应用程序的过程中,可以多使用这些小功能(特性)来让我们的代码更加的优雅~