0

У меня есть базовый контроллер api, который я наследую от ApiController с. В ней я переопределяю ExecuteAsync и хочу использовать некоторые данные, хранящиеся в Principal.Claims var. но он пустой перед вызовом base.ExecuteAsync() и слишком поздно после его вызова. Я не вижу ничего другого, чтобы помочь этому?ApiController переопределяет для доступа User.Claims

public class ApiControllerBase : ApiController 
{ 
    public MyUser CurrentUser { get; set; } 

    public override Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken) 
    { 
     // principal.claims is empty 
     ClaimsPrincipal principal = (ClaimsPrincipal)RequestContext.Principal; // principal.claims is empty 

     var rv = base.ExecuteAsync(controllerContext, cancellationToken); 

     // principal.claims is now populated but the controller.action that inherits from this basecontroller has already fired and thrown an exception since CurrentUser is null. 
     principal = (ClaimsPrincipal)RequestContext.Principal; 
    } 
} 
+2

Вы уверены, что вам нужно переопределить этот метод? Какое поведение вы хотите достичь? – MaKCbIMKo

+0

Я не мог найти другой метод, который можно было бы переопределить. Конечная цель состоит в том, чтобы иметь некоторые свойства на моем базовом ApiController, чтобы наследующие контроллеры могли их использовать. Информация, которую мне нужно загрузить эти свойства, находится в коллекции Principal.Claims. – user3953989

ответ

2

Если вам нужен доступ к претензиям в контроллерах вы можете сделать следующее:

public class MyUser 
{ 
    private readonly ClaimsIdentity _identity; 

    public SeaUser(ClaimsIdentity identity) 
    { 
     _identity= identity; 
    } 

    public IEnumerable<Claim> Claims { get { return _identity.Claims; } } 
} 

public abstract class BaseController : ApiController 
{ 
    private MyUser _user; 

    public new MyUser User 
    { 
     get 
     { 
      return _user ?? (_user = User.Identity != null 
            ? new MyUser((ClaimsIdentity)User.Identity) 
            : null); } 
     } 
    } 
} 

И затем использовать свойство пользователя, куда вам нужно.

Предполагая, что запрос входит в сферу ApiController, порядок работы, как показано ниже:

  • Метод ExecuteAsync из ApiController вызывается.
  • Вызывается метод Initialize для ApiController.
  • Зарегистрированный селектор действий извлекается.
  • Вызывается метод SelectAction зарегистрированного селектора действий. Если согласован только один метод действия, трубопровод продолжается.
  • Все зарегистрированные фильтры для выбранного действия извлекаются.
  • Вызываются авторизационные фильтры. Фильтр авторизации может
    решить, чтобы продолжить выполнение трубопровода или до прекратить конвейер.
  • Если авторизационные фильтры не завершили запрос, выполняются привязки параметров действия .
  • ApiController.ModelState установлен.
  • Вызывается действие фильтра. Фильтры действий принимают решение либо , чтобы продолжить выполнение трубопровода или завершить его.
  • Если Action Filters не завершили запрос, зарегистрировано Действие Захват Invoker.
  • Метод InvokeActionAsync зарегистрированного Action Invoker - это , вызываемый для вызова выбранного метода действий.

Примечание: Если какое-либо исключение возникает из-за выполнения фильтров авторизации для выполнения метода действия, вызывается фильтр исключений.

Есть еще несколько вещей, которые происходят между ними, но это очень близко к полному виду. За дополнительной информацией обращайтесь к ApiController source code.

+0

+1 Это работает, но я хотел бы знать, есть ли способ реализовать его, как я пытаюсь сделать выше. – user3953989

+0

Я добавил несколько заметок в ответ. В соответствии с конвейером выполнения WebAPI невозможно получить принципала до того, как вызывается «ExecuteAsync», потому что он будет инициализирован внутри этого метода. – MaKCbIMKo

0

Вы можете переопределить OnActionExecuting(), который будет вызываться каждый раз, когда вы выполняете действие.

public override void OnActionExecuting(ActionExecutingContext context) 
    { 
     var user = context.HttpContext.User; 
     //store user.Claims in property so inherited controllers have access 
     base.OnActionExecuting(context); 
    } 
+0

Этот метод не существует на System.Web.Http.ApiController – user3953989

+0

, к сожалению, извините. Мое приложение использует ASP.Net Core 1.0, где есть новый класс контроллера –

0

Это работает для меня (Thread.CurrentPrincipal)

public override Task<HttpResponseMessage> ExecuteAsync(HttpControllerContext controllerContext, CancellationToken cancellationToken) 
{ 
    var principal = Thread.CurrentPrincipal as ClaimsPrincipal; 
    return base.ExecuteAsync(controllerContext, cancellationToken); 
} 

Я не уверен, что если порядок регистрации в IAppBuilder (Startup.Configuration) имеет важное значение, но первое, что я зарегистрировать это промежуточное программное обеспечение аутентификации ,

+0

Для меня ** main.Claims.Any() ** возвращает false перед запуском базовой реализации. – user3953989

+0

Вы можете получить претензии на другом этапе? Если нет, вы на 100% уверены, что требования были добавлены при создании билета? – Frode

+0

Да. Если я вместо этого делаю var rv = base.ExecuteAsync (controllerContext, cancelationToken); main.Claims // Это теперь имеет значения. return rv; – user3953989