最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

c# - How to retrieve access token and use for subsequent requests? - Stack Overflow

programmeradmin4浏览0评论

I am creating an ASP.NET Core Web API that is intended to work as a middle ground between several third party API's and a first-party web application to sync data between the third parties and my main application.

My Web API implements a service pattern in its controller to access the data. The first third party API we are integrating with uses token-based authorization, so I have to get a token prior to sending requests for other data. In order to get this token, I have created a private method ValidateExampleToken to see if I have already gotten a valid token, and if so, if that token is still valid based on its timestamp. If either the token is missing or too old, I get another token using the GetExampleToken method.

Controller:

namespace MyService.API.Controllers
{
    [Route("api/[controller]/[action]")]
    [ApiController]
    public class ExampleController : ControllerBase
    {
        private readonly ILogger<ExampleController> _logger;
        private readonly IExampleService _exampleService;

        public ExampleController(ILogger<ExampleController> logger, IExampleService exampleService)
        {
            _logger = logger;
            _exampleService = exampleService;
        }

        [HttpGet(Name = "GetInsured")]
        public async Task<IActionResult> GetInsured(Guid exampleId)
        {
            try
            {
                ExampleInsuredModel? insured = await _exampleService.GetInsured(exampleId);

                if (insured == null)
                    return NoContent();

                return Ok(insured);
            }
            catch (Exception ex)
            {
                return BadRequest(ex.Message);
            }
        }
    }
}

Service:

namespace InsuranceService.ApplicationServices.Services.ExampleService
{
    public class ExampleService : IExampleService
    {
        private readonly ILogger<ExampleService> _logger;
        private readonly HttpClient _exampleClient;
        private ExampleAuthenticationResponseModel _authRespModel;
        private readonly string _exampleUserName;
        private readonly string _examplePassword;
        private readonly int _batchSize;

        public ExampleService(ILogger<ExampleService> logger, HttpClient client, IOptions<ExampleClientSettings> configuration)
        {
            _logger = logger;
            _exampleClient = client;
            _exampleUserName = configuration.Value.UserName ?? throw new ArgumentNullException(_exampleUserName);
            _examplePassword = configuration.Value.Password ?? throw new ArgumentNullException(_examplePassword);
            _batchSize = configuration.Value.BatchResultAmount ?? 0;
            _authRespModel = GetExampleToken().Result;
            _exampleClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(_authRespModel.Token_Type, _authRespModel.Access_Token);
        }

        private async void ValidateExampleToken()
        {
            if (_authRespModel == null || _authRespModel.Expires < DateTime.Now)
            {
                _authRespModel = await GetExampleToken();
                _exampleClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue(_authRespModel.Token_Type, _authRespModel.Access_Token);
            }
        }

        private async Task<ExampleAuthenticationResponseModel> GetExampleToken()
        {
            var body = $"grant_type=password&username={_exampleUserName}&password={_examplePassword}&client_id=ngAuthApp";
            StringContent content = new StringContent(body);
            var response = await _exampleClient.PostAsync("api/token", content);
            if (!response.IsSuccessStatusCode)
            {
                throw new HttpRequestException("Unable to authenticate example credentials");
            }

            var contentString = await response.Content.ReadAsStringAsync();

            if (contentString == null)
            {
                throw new HttpRequestException("Example authentication response is Null.");
            }

            // var respModel = JsonConvert.DeserializeObject<ExampleAuthenticationResponseModel>(contentString);
            var respModel = JsonSerializer.Deserialize<ExampleAuthenticationResponseModel>(contentString);

            if (respModel == null)
                throw new Exception("Unable to deserialize example authentication response.");

            return respModel;
        }

        public async Task<ExampleInsuredModel?> GetInsured(Guid exampleId)
        {
            try
            {
                ValidateExampleToken();
                HttpResponseMessage response = await _exampleClient.GetAsync("?$count=true&$filter=id eq " + exampleId);
                response.EnsureSuccessStatusCode();

                string content = await response.Content.ReadAsStringAsync();

                ExampleInsuredListResponseModel model = JsonSerializer.Deserialize<ExampleInsuredListResponseModel>(content) ?? new ExampleInsuredListResponseModel();

                if (model.Count > 1 || model.Value.Count > 1)
                {
                    throw new Exception($"Multiple insured accounts found with example id {exampleId}");
                }
                else if (model.Count == 1 && model.Value.Count == 1)
                {
                    return model.Value[0];
                }
                else
                {
                    return null;
                }
            }
            catch
            {
                throw;
            }
        }
    }
}

This has been working as I expected for making individual API calls from my web application. Now I am trying to make a series of asynchronous calls to the GetInsured endpoint of the controller to synchronize data for several entities efficiently. The first call to the GetExampleToken method successfully retrieves a token, but subsequent requests come back with a 500 internal server error.

I'm assuming that because those requests are running asynchronously, their API is returning a server error because its trying to generate two tokens for the same credentials at the same time. Normally if I run requests synchronously, I'm not getting this error.

is there a way to set up some middleware to assign this credential to the ExampleService's _exampleClient without having it run on every request and causing this conflict?

发布评论

评论列表(0)

  1. 暂无评论