Web API ExceptionFilter没有在AuthorizationFilter中设置Thread.CurrentPrincipal

时间:2014-04-17 11:54:53

标签: logging exception-handling asp.net-web-api task-parallel-library

在每个请求开始时,我将AuthorizationFilter中的Thread.CurrentPrincipal设置为具有自定义声明的经过身份验证的用户。当我尝试在ExceptionFilter中记录控制器操作中抛出的错误时,从ExceptionFilter中访问的主体与我在AuthorizationFilter中设置的主体不同。事实上,我在ExceptionFilter中获得的主体是在我在AuthorizationFilter中更改之前在线程上存在的主体。在浏览了Web API的源代码之后,我想我发现了与任务执行上下文相关的问题(参见ApiController类,ExecuteAsync方法)。下面的示例代码是重现问题的简单方法:

class Program
{
    static void Main(string[] args)
    {
        SetIdentity("originIdentity");

        Func<Task> controllerAction = () =>
        {
            Console.WriteLine("Identity is correct in controller: " + Thread.CurrentPrincipal.Identity.Name);

            return Task.FromResult("result");
        };

        Func<Task> authFilter = async () =>
        {
            SetIdentity("newIdentity");
            Console.WriteLine("Set identity to " + Thread.CurrentPrincipal.Identity.Name);

            await controllerAction();
        };

        Func<Task> exceptionFilter = async () =>
        {
            Console.WriteLine("Original identity: " + Thread.CurrentPrincipal.Identity.Name);

            //there would be a try block around this so we can catch exceptions
            await authFilter();

            Console.WriteLine("Identity is what it was before: " + Thread.CurrentPrincipal.Identity.Name);
        };

        exceptionFilter().Wait();

        Console.Read();
    }

    private static void SetIdentity(string originidentity)
    {
        var originIdentity = new ClaimsIdentity("HeaderAuthentication");
        originIdentity.AddClaim(new Claim(ClaimTypes.Name, originidentity));
        Thread.CurrentPrincipal = new ClaimsPrincipal(originIdentity);
    }
}

输出:

Original identity: originIdentity
Set identity to newIdentity
Identity is correct in controller: newIdentity
Identity is what it was before: originIdentity

我的问题是:

  1. 我看到了我认为我看到了什么吗?
  2. 这是一个错误还是Web API中的设计? TPL的行为是有道理的,但很难想象这是Web API中的预期行为
  3. 在Web API中推荐/干净的方法是什么?

1 个答案:

答案 0 :(得分:4)

Thread.CurrentPrincipal在某些线程/并行情况下存在一些问题。

这就是它在Web API v2中不再使用的原因。在HttpRequestMessage上使用GetRequestContext()扩展方法来获取当前用户/或设置它