【问题标题】:Best practices for passing in API key in ASP.NET Core MVC在 ASP.NET Core MVC 中传递 API 密钥的最佳实践
【发布时间】:2021-09-24 15:09:12
【问题描述】:

我正在使用 MVC 在 ASP.NET 核心中开发一个简单的天气仪表板。我已经弄清楚如何将天气 API 调用的 URI 基地址从 appsettings 传递到配置设置,然后再传递到调用天气 API 的接口:

应用设置:

    {
      "Logging": {
        "LogLevel": {
          "Default": "Information",
          "Microsoft": "Warning",
          "Microsoft.Hosting.Lifetime": "Information"
        }
      },
      "AllowedHosts": "*",
      //Here:
      "openWeatherAPI": "https://api.openweathermap.org/",
    }
  

启动配置:

   

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

        public IConfiguration Configuration { get; }

        public void ConfigureServices(IServiceCollection services)
        {
            //Here
            string uri = Configuration.GetValue<string>("openWeatherAPI");

            services.AddControllersWithViews();

            services.AddHttpClient<IForecastRepository, ForecastRepository>(c =>  
                {
                    //And Here:
                    c.BaseAddress = new Uri(uri);
                }
                );

预测界面:

 

    public interface IForecastRepository
        {
            Task<CityModel> GetMovieDetailsAsync(string cityName);
        }
    
        public class ForecastRepository : IForecastRepository
        {     
                private readonly HttpClient _httpClient;
    
            public ForecastRepository(HttpClient httpClient)
                {
                    _httpClient = httpClient;       
            }
    
    
            public async Task<CityModel> GetMovieDetailsAsync(string cityName)
            {
                string IDOWeather = "/*my api key is hardcoded in here*/";
                var queryString = $"data/2.5/weather?q={cityName}&units=imperial&APPID={IDOWeather}";
                var response = await _httpClient.GetStringAsync(queryString);
    
             //...code conitnues

有没有类似的方法可以传入 API 密钥?据我了解,将其写入我所做的应用程序并不是最佳做法。

关于 HttpClientFactory 的讨论:

天气控制器:

    public class WeatherController : Controller
    {


        private readonly IForecastRepository _forecastRepository;
        
        public WeatherController(IForecastRepository forecastRepository)
        {
            _forecastRepository = forecastRepository;
        }

        public IActionResult SearchCity()
        {
            var viewModel = new CityModel();
            return View(viewModel);
        }

        public IActionResult City()
        {
            var viewModel = new CityModel();
            return View(viewModel);
        }


        [HttpPost]
        public async Task<IActionResult> SearchResults(CityModel titleFromView)
        {

            var movieDetail = await _forecastRepository.GetMovieDetailsAsync(titleFromView.Name);
            return View("City", movieDetail);
      

【问题讨论】:

  • 为什么不能像传入 API URI 那样做呢?可能的优化:使用属性UriApiKey 创建一个类OpenWeatherApiOptions。在启动时从 appsettings 填写它,并将其作为 IOptions&lt;OpenWeatherApiOptions&gt; 注入到您的预测存储库中 - 详细信息在 @galdin 链接的文档中进行了解释
  • 我没看过那个文档,谢谢分享!我迷失在 httpclient/httpclientfactory 文档中,并没有考虑真正阅读我正在工作的更广泛的上下文(即配置)。我最终使用了提供的答案中的建议。配置文档中概述的方法与答案中演示的方法之间是否存在任何既定的偏好?

标签: c# asp.net-core .net-core model-view-controller api-key


【解决方案1】:

试试这个代码

 public class ForecastRepository : IForecastRepository
{     
   private readonly HttpClient _httpClient;
   private readonly string _apiKey;

 public ForecastRepository(HttpClient httpClient, IConfiguration configuration)
 {
     _httpClient = httpClient;   
     _apiKey  = configuration.GetValue<string>("idoWeather");
      //or
     _apiKey  = configuration["idoWeather"];
}
    
 public async Task<CityModel> GetMovieDetailsAsync(string cityName)
  {
    string IDOWeather = _apiKey;

    var queryString = $"data/2.5/weather?q={cityName}&units=imperial&APPID={IDOWeather}";
   var response = await _httpClient.GetStringAsync(queryString);
    
             //...code conitnues
    }

应用设置:

   {
      ....
      "idoWeather": "apikey",
      "openWeatherAPI": "https://api.openweathermap.org/",
    }

顺便说一句,我强烈建议您使用 HttpClientFactory。如果您需要具有不同 url 的 httpClient,则必须以某种方式更改 baseUrl。您可以在启动时创建一组类型化或命名的 http 客户端,但由于您通常不需要所有这些客户端,因此最好在需要时创建。 有关更多信息,您可以阅读我的另一个答案https://stackoverflow.com/a/69054959/11392290

private readonly IHttpClientFactory _clientFactory
private readonly IConfiguration _configuration;

 public ForecastRepository(IHttpClientFactory clientFactory, IConfiguration configuration)
 {
    _configuration=configuration;
    _clientFactory = clientFactory;
  
}
 
public async Task<CityModel> GetMovieDetailsAsync(string cityName)
  {
 
 var baseAddress = _configuration.GetValue<string>("openWeatherAPI");
   var  IDOWeather = _configuration.GetValue<string>("idoWeather");
      //or
     var baseAddress = _configuration["openWeatherAPI"];
      var  IDOWeather  = _configuration["idoWeather"];

var queryString = $"data/2.5/weather?q={cityName}&units=imperial&APPID={IDOWeather}";

var httpClient = _clientFactory.CreateClient();
httpClient.BaseAddress = new Uri(baseAddress);
 var response = await httpClient.GetStringAsync(queryString);

使用工厂替换

 services.AddHttpClient<IForecastRepository, ForecastRepository>(c =>  
 {
     //And Here:
                    c.BaseAddress = new Uri(uri);
   }
);

services.AddHttpClient();

由于您使用的是存储库,因此您必须将其添加到 DI 服务中

services.AddScoped<IForecastRepository , ForecastRepository>();

【讨论】:

  • 他已经在使用HttpClientFactoryAddHttpClient&lt;&gt; 在这里发挥了魔力,并且按照推荐的方式实现(至少是如何获取 HttpClient 实例的部分)-docs.microsoft.com/en-us/dotnet/architecture/microservices/…
  • @ChristophLütjen 感谢您的通知。我只是向 PO 展示了另一种更灵活的方式,恕我直言。使用什么由他决定。
  • 是的,在我看来,您的服务好像可以注册为“普通”服务(然后它应该注入工厂)或作为类型化的 http 客户端(然后它应该注入客户直接)?
  • @ChristophLütjen 是的,我更新了答案。
  • @Serge 感谢您的回答,成功了!
猜你喜欢
  • 2019-07-30
  • 2020-08-07
  • 2011-03-08
  • 1970-01-01
  • 2022-11-03
  • 1970-01-01
  • 2010-11-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多