在 ASP.NET 核心 MVC 中传递 API 键的最佳实践

Best practices for passing in API key in ASP.NET Core MVC

我正在使用 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);
      

试试这个代码

 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 客户端,但由于您通常不需要所有这些客户端,因此最好在需要时创建。 有关更多信息,您可以阅读我的另一个答案

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>();