Здравствуйте.
Столкнулся с проблемой потери ClaimsPrincipal в процессе работы провайдеров OAuth2 middleware. Суть её вот в чем:
Для логирования мне необходимо генерировать Guid в качестве Activity Id. Этот гуид затем используется при вызовах различных датасорсов, чтобы все логи имели единый айди в рамках одного запроса. Так как OAuth middleare зарегистрирован первым, то он и генерирует новое значение activity Id и сохраняет его в клэймах:
public override Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var claimsPrincipal = Thread.CurrentPrincipal as ClaimsPrincipal;
claimsPrincipal.Identities.First.AddClaim(new Claim("TestClaim", Guid.NewGuid().ToString()));
// много различных асинхронных вызовов датасорсов которые логируются, например:
await userDataSource.FindAsync(id);
await tenantDataSource.FindAsync(id);
//
}
При вызове метода датасорса, из CurrentPrincipal извлекается клэйм и его значение передается в логгер.
И всё вроде бы хорошо, но если до и во время вызова userDataSource клэйе присутствует, то после завершения его вызова и до вызова tenantDataSource клэйма уже нет.
Решив, что owin запускает все middleware с ConfigureAwait(false) что приводит к потере контекста, вынес вызовы датасорсов в отдельный метод, который вызвал c ConfigureAwait(true) в надежде, что контекст не потеряется:
await Grant().ConfigureAwait(true);
Но это не помогло и после возврата из первого асинхронного вызова принципал теряется.
Если же я устанавливаю клэйм в методе Api контроллера, то он доступен на протяжении всего вызова сколько бы ни было внутри вызовов.
Это какая-то особая магия работы с OWIN? Подскажите, пожалуйста, почему это происходит и как предотвратить потерю принципла с установленными мною клэймами?
PS. Еще один интересный для себя нюанс обнаружил:
Если смотреть в Principal в контроллере, то его Identity и Identities[0] ссылаются на один объект, когда как внутри middleware Identity и Identities[0] - два разных экземпляра. Более того, в отличие от контроллера, где Principal - ClaimsPrincipal, внутри middleware он - GenericPrincipal.
Инфы, почему это так, я, к сожалению, не нашел. Буду рад, если кто-нибудь кинет ссылку почитать.
Update
Квыряясь дальше, наткнулся, что в контексте овина Request.User == null. Создав новый принципал и занеся его в User, CurrentPrincipal перестал теряться, и более того, он ссылается на инстанс, занесенный мною в Request.User.
Но я до сих пор не могу найти инфы почему такое происходит и с чего вдруг при возврате контекста из await принципал восстанавливается из Request.User.
Буду рад если кто разъяснит этот момент.