Asp.net mvc 如何处理空HttpContext.Current,当使用异步/等待身份验证筛选器时?
在控制器中的一个API中,我需要引用HttpContext.Current。在我实现自定义身份验证过滤器之前,一切正常。过滤器使用异步方法和wait。但是,当过滤器就位时,HttpContext.Current在到达我的控制器时为空。Asp.net mvc 如何处理空HttpContext.Current,当使用异步/等待身份验证筛选器时?,asp.net-mvc,asp.net-web-api,asp.net-web-api2,Asp.net Mvc,Asp.net Web Api,Asp.net Web Api2,在控制器中的一个API中,我需要引用HttpContext.Current。在我实现自定义身份验证过滤器之前,一切正常。过滤器使用异步方法和wait。但是,当过滤器就位时,HttpContext.Current在到达我的控制器时为空。我假设这是因为我的控制器由于过滤器中的async/await而在不同的线程上执行。如果是这样,我应该如何访问控制器中的“原始”上下文?这有点令人失望,因为过滤器似乎是一个很好的可插拔想法,但不幸的是,它们有一些[严重的]缺点。示例伪代码: public class
我假设这是因为我的控制器由于过滤器中的async/await而在不同的线程上执行。
如果是这样,我应该如何访问控制器中的“原始”上下文?
这有点令人失望,因为过滤器似乎是一个很好的可插拔想法,但不幸的是,它们有一些[严重的]缺点。
示例伪代码:
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;
}
}
公共类TestAuthFilter:属性,IAAuthenticationFilter
{
私有静态字符串validationClaim=“testClaim”;
私有令牌验证URI;
public bool AllowMultiple{get{return false;}
公共TestAuthFilter(字符串令牌验证URI)
{
this.tokenValidationUri=tokenValidationUri;
}
公共任务ChallengeAsync(HttpAuthenticationChallengeContext,CancellationToken CancellationToken)
{
//我们不会向响应添加任何身份验证挑战
返回Task.FromResult(0);
}
公共异步任务AuthenticateAsync(HttpAuthenticationContext上下文,CancellationToken CancellationToken)
{
HttpRequestMessage请求=context.request;
AuthenticationHeaderValue authorization=request.Headers.authorization;
if(授权==null)
{
返回;
}
if(authorization.Scheme!=“持票人”)
{
返回;
}
if(String.IsNullOrEmpty(authorization.Parameter))
{
context.ErrorResult=新身份验证失败结果(“缺少访问令牌”,请求);
返回;
}
string token=authorization.Parameter;
IPrincipal principal=await authenticatesync(令牌、取消令牌);
if(principal==null)
{
context.ErrorResult=新身份验证失败结果(“无效访问令牌”,请求);
}
其他的
{
context.Principal=Principal;
}
}
公共异步任务AuthenticateAsync(字符串令牌、取消令牌取消令牌)
{
使用(HttpClient=new HttpClient())
{
尝试
{
HttpResponseMessage response=wait client.GetAsync(tokenValidationUri+token,cancellationToken);
使用(HttpContent=response.content)
{
字符串结果=等待内容。ReadAsStringAsync();
如果(结果!=null)
{
if(响应。IsSuccessStatusCode)
{
var success=wait response.Content.ReadAsAsync();
if(success.audition.Equals(validationaudition,StringComparison.Ordinal))
{
TestPrincipal=新的TestPrincipal([…]);
返还本金;
}
}
其他的
{
var error=wait response.Content.ReadAsAsync();
}
}
}
}
捕获(HttpRequestException e)
{
WriteLine(“异常:{0}”,e.Message);
}
}
返回null;
}
}
如果有任何建议,我将不胜感激。
谢谢。在
WebAPI
中有一个关于authenticateSync
的好链接:
应将作为参数HttpAuthenticationContext
,该参数包含ActionContext
和HttpRequestMessage
请求的线程安全版本
以下是到达该位置的继承链:
(HttpRequestMessage)System.Web.Http.Filters.HttpAuthenticationContext.ActionContext.ControllerContext.Request
解决方案是在web.config中包含“targetFramework=4.5”。积分归Stephen Cleary所有-请参阅上面的注释。将上下文作为参数传递。如何将上下文作为参数传递给控制器?这意味着我应该能够在某个点获取“原始”上下文,然后将其传递给控制器。但是,我的控制器的方法是由框架调用的。您能详细说明一下吗?您能提交您的自定义筛选器吗?您的
AuthenticationFilter
必须具有OnAuthentication()
方法。你也可以提交吗。还有,您在哪里调用了HttpContext.Current
我在您的代码中找不到它。@bdristan:您的目标是.NET 4.5,并且设置了httpRuntime@targetFramework
到4.5
在web.config
中?