Using ASP.NET WebAPI, during authentication, Thread.CurrentPrincipal
is set so that controllers can later use the ApiController.User
property.
If that authentication step becomes asynchronous (to consult another system), any mutation of CurrentPrincipal
is lost (when the caller's await
restores the synchronization context).
Here's a very simplified example (in the real code, authentication happens in an action filter):
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's 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;
}
}
How do you set Thread.CurrentPrincipal
in an async function such that the caller's await
doesn't discard that mutation when restoring the synchronization context?
DelegatingHandler
which does authentication before it gets to the controller. – Mellissamellitz