Установить Thread.CurrentPrincipal асинхронно?

Используя ASP.NET WebAPI, во время аутентификации Thread.CurrentPrincipal устанавливается так, что контроллеры могут позже использовать свойство ApiController.User.

Если этот шаг аутентификации становится асинхронным (для проверки другой системы), любая мутация CurrentPrincipal теряется (когда вызывающий await восстанавливает контекст синхронизации).

Здесь очень упрощенный пример (в реальном коде аутентификация происходит в фильтре действий):

using System.Diagnostics;
using System.Security.Principal;
using System.Threading;
using System.Threading.Tasks;

public class ExampleAsyncController : System.Web.Http.ApiController
{
    public async Task GetAsync()
    {
        await AuthenticateAsync();

        // The await above saved/restored the current synchronization
        // context, thus undoing the assignment in AuthenticateAsync(). 
        Debug.Assert(User is GenericPrincipal);
    }

    private static async Task AuthenticateAsync()
    {
        // Save the current HttpContext because it null after await.
        var currentHttpContext = System.Web.HttpContext.Current;

        // Asynchronously determine identity.
        await Task.Delay(1000);
        var identity = new GenericIdentity("<name>");

        var roles = new string[] { };
        Thread.CurrentPrincipal = new GenericPrincipal(identity, roles);
        currentHttpContext.User = Thread.CurrentPrincipal;
    }
}

Как вы устанавливаете Thread.CurrentPrincipal в async-функции, чтобы вызывающий await не отбрасывал эту мутацию при восстановлении контекста синхронизации?

Ответ 1

Вы также должны установить HttpContext.Current.User. См. этот ответ и этот пост в блоге для получения дополнительной информации.

Обновление: Также убедитесь, что вы работаете на .NET 4.5 и UserTaskFriendlySynchronizationContext установлен на true.