0

我有一个基地API控制器我从ApiController与继承。在这里,我重写了ExecuteAsync并希望使用存储在Principal.Claims变量中的一些数据。但在调用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范围,操作顺序是如下:

  • 的ApiController的ExecuteAsync方法被调用。
  • 调用ApiController的Initialize方法。
  • 检索已注册的动作选择器。
  • 调用注册动作选择器的SelectAction方法。 如果只有一个操作方法匹配,则流水线继续。
  • 检索所选操作的所有注册过滤器。
  • 授权过滤器被调用。授权过滤器可以决定让流水线继续执行还是让 终止流水线。
  • 如果授权过滤器未终止请求,则执行参数绑定操作 。
  • ApiController.ModelState已设置。
  • 动作过滤器被调用。动作过滤器决定要么 让管道继续执行或终止管道。
  • 如果动作过滤器没有终止请求,注册动作 调用者被检索。
  • 注册动作调用者的InvokeActionAsync方法是 调用来调用选定的动作方法。

注意:如果从执行授权过滤器到执行操作方法时发生任何异常,将调用异常过滤器。

还有几件事发生在两者之间,但这非常接近完整视图。查看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核心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

对我来说** principal.Claims.Any()**在运行基础实现之前返回false。 – user3953989

+0

你能够在另一阶段检索索赔?如果没有,您是否100%确定在创建票证时添加了索赔? – Frode

+0

是的。如果我反而做 var rv = base.ExecuteAsync(controllerContext,cancellationToken); principal.Claims //现在具有值。 return rv; – user3953989