Претензии Auth с OWIN Self Hosted WebApi

Я самостоятельно размещаю WebApi со следующей конфигурацией:

Visual Studio 2012/.NET 4.0

public void Configuration(IAppBuilder appBuilder)
{
    var config = new HttpConfiguration();

    // authentication
    config.MessageHandlers.Add(new Shield.PresharedKeyAuthorizer());

    // routing
    config.Routes.MapHttpRoute(
        name: "Default",
        routeTemplate: "{controller}/{id}",
        defaults: new { id = RouteParameter.Optional }
    );

    appBuilder.UseWebApi(config);
}

У меня есть простая тестовая установка со следующим DelegatingHandler, чтобы создать заявку и прикрепить ее к текущему потоку.

public class PresharedKeyAuthorizer : DelegatingHandler
{
    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, System.Threading.CancellationToken cancellationToken)
    {
        var claims = new List<Claim>();
        claims.Add(new Claim(ClaimTypes.Name, "superstar"));

        var identity = new ClaimsIdentity(claims, "PresharedKey");
        var principal = new ClaimsPrincipal(identity);

        Thread.CurrentPrincipal = principal;
        if (HttpContext.Current != null)
            HttpContext.Current.User = principal;

        return base.SendAsync(request, cancellationToken);
    }
}

Однако, когда я нажимаю ApiController, который помечен атрибутом Authorize, он не распознает аутентификацию.

[Authorize]
public class FilesController : ApiController
{
    public IEnumerable<string> Get()
    {
        return new string[] { "Secure File A", "Secure File B" };
    }
}

Удаление атрибута Authorize и установка точки останова, я вижу, что свойство RequestContext.Principal действительно равно null. Запрос работает без атрибута Authorize, поэтому я знаю, что настройка собственного хостинга верна, но я должен что-то пропускать в конвейере аутентификации.

Что мне не хватает, чтобы разрешить эту претензию работать с атрибутом Authorize?

Этот связанный ответ с тем же подходом, похоже, работает при размещении в IIS: qaru.site/info/209262/...

Ответ 1

В обработчике сообщений установите такой главный.

request.GetRequestContext().Principal = principal;

Не используйте

Thread.CurrentPrincipal = principal;

if (HttpContext.Current != null)
    HttpContext.Current.User = principal;

UPDATE

Прошло некоторое время с тех пор, как я работал над .NET 4.0/2012/Web API < 2. Поэтому я не могу ответить точно. Но с хостингом OWIN, основной должен быть установлен в контексте OWIN. OwinHttpRequestContext устанавливает как Thread.CurrentPrincipal, так и главный в контексте OWIN. Используя request.GetRequestContext().Principal, эти данные скрыты от вас. Короче говоря, я верю, если вы каким-то образом зададите принципала в контексте OWIN, это сработает. Не знаете, как это сделать из обработчика сообщений веб-API. Вы можете сделать это из промежуточного программного обеспечения OWIN.

public void Configuration(IAppBuilder app)
{
    var config = new HttpConfiguration();
    config.Routes.MapHttpRoute("default", "api/{controller}/{id}");

    //config.MessageHandlers.Add(new PresharedKeyAuthorizer());

    app.Use((IOwinContext context, Func<Task> next) =>
    {
        var claims = new List<Claim>();
        claims.Add(new Claim(ClaimTypes.Name, "superstar"));

        var identity = new ClaimsIdentity(claims, "PresharedKey");
        var principal = new ClaimsPrincipal(identity);

        context.Request.User = principal;
        return next.Invoke();
    });

    app.UseWebApi(config);
}