웹 서비스를 호출하는 UWP 앱을 개발하고 있습니다. 이를 위해 Windows.Web.Http 네임 스페이스의 HttpClient 객체를 사용하고 생성자에 IHttpFilter 객체를 전달합니다. 이 필터는 인증 프로세스를 담당합니다. 나는이 솔루션을 기반으로 link이고 인증 로직은 this을 기반으로합니다.IHttpFilter.SendRequestAsync에서 예기치 않은 시간에 메서드가 호출되었습니다.
내가 뭘 잘못하고 있는지 모르겠지만이 예외가 있습니다. 예기치 않은 시간에 메서드가 호출되었습니다. (HRESULT 예외 : 0x8000000E)
테스트중인 시나리오는 유효하다고 간주 되더라도 토큰이 유효하지 않은 경우입니다. 이 경우 (now> TokenManager.Token.ExpiresOn) 조건이 false 인 경우 권한 부여 헤더가 추가되고 (유효하지 않은 토큰과 함께) 요청이 전송 된 다음 http 응답 코드와 www-authenticate 헤더가 검사되고 if 재 시도를 수행하려면 새로 고침 토큰을 사용하여 새 액세스 토큰을 요청해야합니다. 예외가 throw 될 때이 줄에 도달했을 때 (두 번째) : 응답 = InnerFilter.SendRequestAsync (요청)을 기다립니다 .AsTask (cancellationToken, progress);
내가 뭘 잘못하고 있는지 전혀 모르겠다. 나는 사람들이이 오류를 가지고있는 또 다른 질문을 보았다. 대개 작업의 완료를 기다리지 않고 작업 결과를 얻으려고하지만 모든 비동기 메서드에서 await 키워드를 사용하기 때문이다.
public class AuthFilter : HttpFilter
{
public override IAsyncOperationWithProgress<HttpResponseMessage, HttpProgress> SendRequestAsync(HttpRequestMessage request)
{
return AsyncInfo.Run<HttpResponseMessage, HttpProgress>(async (cancellationToken, progress) =>
{
var retry = true;
if (TokenManager.TokenExists)
{
var now = DateTimeOffset.UtcNow.ToUnixTimeSeconds();
if (now > TokenManager.Token.ExpiresOn)
{
retry = false;
await RefreshTokenAsync();
}
request.Headers.Authorization = new HttpCredentialsHeaderValue(TokenManager.Token.TokenType, TokenManager.Token.AccessToken);
}
HttpResponseMessage response = await InnerFilter.SendRequestAsync(request).AsTask(cancellationToken, progress);
cancellationToken.ThrowIfCancellationRequested();
if (response.StatusCode == HttpStatusCode.Unauthorized)
{
var authHeader = response.Headers.WwwAuthenticate.SingleOrDefault(x => x.Scheme == "Bearer");
if (authHeader != null)
{
var challenge = ParseChallenge(authHeader.Parameters);
if (challenge.Error == "token_expired" && retry)
{
var success = await RefreshTokenAsync();
if (success)
{
request.Headers.Authorization = new HttpCredentialsHeaderValue(TokenManager.Token.TokenType, TokenManager.Token.AccessToken);
response = await InnerFilter.SendRequestAsync(request).AsTask(cancellationToken, progress);
}
}
}
}
return response;
});
}
private async Task<bool> RefreshTokenAsync()
{
using (var httpClient = new HttpClient())
{
httpClient.DefaultRequestHeaders.Accept.Add(new HttpMediaTypeWithQualityHeaderValue("application/json"));
var content = new HttpStringContent(JsonConvert.SerializeObject(new { RefreshToken = TokenManager.Token.RefreshToken }), UnicodeEncoding.Utf8, "application/json");
var response = await httpClient.PostAsync(SettingsService.Instance.WebApiUri.Append("api/login/refresh-token"), content);
if (response.IsSuccessStatusCode)
TokenManager.Token = JsonConvert.DeserializeObject<Token>(await response.Content.ReadAsStringAsync());
return response.IsSuccessStatusCode;
}
}
private (string Realm, string Error, string ErrorDescription) ParseChallenge(IEnumerable<HttpNameValueHeaderValue> input)
{
var realm = input.SingleOrDefault(x => x.Name == "realm")?.Value ?? string.Empty;
var error = input.SingleOrDefault(x => x.Name == "error")?.Value ?? string.Empty;
var errorDescription = input.SingleOrDefault(x => x.Name == "error_description")?.Value ?? string.Empty;
return (realm, error, errorDescription);
}
public override void Dispose()
{
InnerFilter.Dispose();
GC.SuppressFinalize(this);
}
}
public abstract class HttpFilter : IHttpFilter
{
public IHttpFilter InnerFilter { get; set; }
public HttpFilter()
{
InnerFilter = new HttpBaseProtocolFilter();
}
public abstract IAsyncOperationWithProgress<HttpResponseMessage, HttpProgress> SendRequestAsync(HttpRequestMessage request);
public abstract void Dispose();
}
편집 :
이 링크 (link, link)에 따르면, 내가 두 번 같은 요청을 보낼 수없는 것 같다. 하지만 다른 인증 헤더를 사용하여 동일한 요청을 다시 보내야합니다. 어떻게하면 될까요?