【问题标题】:User secrets not available to .net core app hosted in windows serviceWindows 服务中托管的 .net 核心应用程序无法使用用户机密
【发布时间】:2017-05-24 15:31:36
【问题描述】:

我正在尝试访问 .Net Core Windows 服务中的用户机密。服务本身在服务帐户下运行,我为服务用户添加了用户密码。

将应用程序作为简单的控制台应用程序运行时,可以访问用户密码。但是,将应用程序作为 Windows 服务运行时,无法读取该设置。没有错误 - 只是没有获得值。该服务在与登录用户相同的用户帐户下运行 - 并且可以在运行控制台应用程序时获取密钥。

当我将 secrets.json 文件添加到托管可执行文件的位置并使用 AddJsonFile 方法读取它时,可以读取该值。这是一个代码sn-p:

    public Startup(IHostingEnvironment env)
    {
        var builder = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
            .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);

        builder.AddEnvironmentVariables();

        // does not work as a service
        builder.AddUserSecrets("TestUserSecrets");

        // works as a service when secrets.json is copied to exe directory
        // builder.AddJsonFile(Path.Combine(Directory.GetCurrentDirectory(), "Secrets.json"));

        Configuration = builder.Build();

        Log.Logger = new LoggerConfiguration()
            .ReadFrom.Configuration(Configuration)
            .CreateLogger();
    }

    public IConfigurationRoot Configuration { get; set; }


    public void Configure(IApplicationBuilder app, ILoggerFactory logFactory)
    {
        // attempt to obtain secret config value
        string secret = Configuration["Secret"];

Windows 服务访问用户密码(在 secret.json 文件中)是否存在问题?

是否打算将用户机密用于开发,因此在 Windows 服务中使用用户机密是行不通的?

【问题讨论】:

  • 服务的运行时环境与控制台应用程序的运行环境完全不同。从 Directory.GetCurrentDirectory() 开始,通常是一个非常丑陋的全局变量,它只设置在您希望它偶然出现的位置,它不是您的应用所在的位置。 env.EnvironmentName 非常值得怀疑,服务不是 ASP.NET 应用程序。
  • 内置的 usersecrets 配置提供程序目前无法在 IIS Express 之外的多个环境(包括常规 IIS,可能还有 Windows 服务)中从适当的基本目录构建。 %AppData% 在这些情况下最终位于 windows 目录中,因此结果找不到 secrets.json。然后它默认在根程序目录中查找 secrets.json,当它找不到时不加载任何内容。我不想编写自定义提供程序,只是将环境变量用于开发机密。

标签: c# .net-core appsettings


【解决方案1】:

首先,你应该看一下关于Accessing user secrets via configuration的文档

该文档将帮助您了解如何正确使用用户机密。

你注意到了

builder.AddUserSecrets("TestUserSecrets");

无法正常工作...查看下面的代码块,了解我如何调整您的代码以符合文档要求:

public Startup(IHostingEnvironment env)
{
    var builder = new ConfigurationBuilder()
        .SetBasePath(Directory.GetCurrentDirectory())
        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
        .AddUserSecrets<Startup>(); // <-- note here
        .AddEnvironmentVariables();

    Configuration = builder.Build();
}

public IConfigurationRoot Configuration { get; }

public void ConfigureServices(IServiceCollection services)
{
    string testSecret = Configuration["Secret"];
}

Secret Manager 工具的工作原理

Secret Manager 工具抽象出实现细节,例如值的存储位置和方式。您可以在不了解这些实现细节的情况下使用该工具。 在当前版本中,这些值存储在用户配置文件目录中的 JSON 配置文件中:

  • Windows:%APPDATA%\microsoft\UserSecrets\&lt;userSecretsId&gt;\secrets.json
  • Linux:~/.microsoft/usersecrets/&lt;userSecretsId&gt;/secrets.json
  • 苹果机:~/.microsoft/usersecrets/&lt;userSecretsId&gt;/secrets.json

userSecretsId 的值来自.csproj 文件中指定的值。 您不应编写取决于使用 Secret Manager 工具保存的数据的位置或格式的代码,因为这些实施细节可能会发生变化。例如,秘密值目前尚未加密,但可能有一天会加密。


替代解决方案

我确实遇到了与您经常尝试使用 Secret Manager 工具相同的情况(并不适合所有人,也不是所有情况)。

我的典型解决方案是做你已经注意到的:

var builder = new ConfigurationBuilder()
    .SetBasePath(Directory.GetCurrentDirectory())
    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
    .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
    .AddEnvironmentVariables();

try
{
    string secretsFile = Path.GetFullPath("../secrets.json");
    builder.AddJsonFile(secretsFile , optional: true, reloadOnChange: true);
}
catch (UnauthorizedAccessException) { } // this resolves an error from hosts trying to go 
                                        // below the root.

如您所见,它将尝试从提供的路径中获取secrets.json 文件。但是,您应该注意,如果您托管应用程序,您很可能会将它们存储到环境变量中,否则这种情况已经很好了。否则,只需调整代码以满足您的特定环境。

注意:

string secretsFile = Path.GetFullPath("../secrets.json");

我故意在这里弹出了secrets.json根目录下,因为如果您使用任何源代码管理,我们不想不小心将我们的secrets.json 放入存储库中。 p>

【讨论】:

    【解决方案2】:

    我的替代解决方案是使用option,它将具有 IConfiguration 类型属性。在构造函数中调用IOptions 而不是Iconfiguration

    MyOptions.cs

    public class MyOptions
    {
        public IConfiguration Configuration { get; set; }
    }
    

    Startup.cs

    public class Startup
            {    
                public Startup(IHostingEnvironment env)
                {
                    var builder = new ConfigurationBuilder()
                        .SetBasePath(env.ContentRootPath)
                        .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
                        .AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
    
                    if (env.IsDevelopment())
                    {
                        builder.AddUserSecrets<Startup>();
                    }
                    else
                    {
                        builder.AddEnvironmentVariables();
                    }
    
                    Configuration = builder.Build();
                }
    
                public IConfiguration Configuration { get; }
    
                public void ConfigureServices(IServiceCollection services)
                {
                    services.Configure<MyOptions>(opt =>
                    {
                        opt.Configuration = Configuration;
                    });
    
                    services.AddDbContext<ApplicationDbContext>(options =>
                        options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
                }
            }
    

    然后像访问它

    using Microsoft.Extensions.Options;
    public class MyController
        {
            readonly IConfiguration _configuration;
            public MyController(IOptions<MyOptions> options)
            {
                _configuration = options.Value.Configuration;
            }
    
            public void Test()
            {
                Console.Log(_configuration["Section:Value"]);
            }
        }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-09-26
      • 1970-01-01
      • 1970-01-01
      • 2020-12-13
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-10-05
      相关资源
      最近更新 更多