In one of apis in my controller I need to reference HttpContext.Current. Everything worked fine until I implemented a custom authentication filter. The filter uses async methods with await. However, with the filter in place, the HttpContext.Current is null when it reaches my controller.
I'm assuming that this is because my controller executes on a different thread that it used to due to async/await in the filter.
If this is the case, how should I access the 'original' context in my controller?
This is a bit disappointing because filters seem like a good pluggable idea but unfortunately they come with some [serious] disadvantages.
Sample pseudo code:
public class TestAuthFilter : Attribute, IAuthenticationFilter
{
private static string validationClaim = "testClaim";
private tokenValidationUri;
public bool AllowMultiple { get { return false; } }
public TestAuthFilter(string tokenValidationUri)
{
this.tokenValidationUri = tokenValidationUri;
}
public Task ChallengeAsync(HttpAuthenticationChallengeContext context, CancellationToken cancellationToken)
{
// We are not adding any authentication challenges to the response
return Task.FromResult(0);
}
public async Task AuthenticateAsync(HttpAuthenticationContext context, CancellationToken cancellationToken)
{
HttpRequestMessage request = context.Request;
AuthenticationHeaderValue authorization = request.Headers.Authorization;
if (authorization == null)
{
return;
}
if (authorization.Scheme != "Bearer")
{
return;
}
if (String.IsNullOrEmpty(authorization.Parameter))
{
context.ErrorResult = new AuthenticationFailureResult("Missing access token", request);
return;
}
string token = authorization.Parameter;
IPrincipal principal = await AuthenticateAsync(token, cancellationToken);
if (principal == null)
{
context.ErrorResult = new AuthenticationFailureResult("Invalid access token", request);
}
else
{
context.Principal = principal;
}
}
public async Task<IPrincipal> AuthenticateAsync(string token, CancellationToken cancellationToken)
{
using (HttpClient client = new HttpClient())
{
try
{
HttpResponseMessage response = await client.GetAsync(tokenValidationUri + token, cancellationToken);
using (HttpContent content = response.Content)
{
string result = await content.ReadAsStringAsync();
if (result != null)
{
if (response.IsSuccessStatusCode)
{
var success = await response.Content.ReadAsAsync<TokenValidationSuccess>();
if (success.audience.Equals(validationAudience, StringComparison.Ordinal))
{
TestPrincipal principal = new TestPrincipal([...]);
return principal;
}
}
else
{
var error = await response.Content.ReadAsAsync<TokenValidationError>();
}
}
}
}
catch (HttpRequestException e)
{
Debug.WriteLine("Exception: {0}", e.Message);
}
}
return null;
}
}
I'd appreciate any suggestions.
Thanks.