ApiController 重写以访问 User.Claims

ApiController override to access User.Claims

我有一个从 ApiController 继承的基础 api 控制器。在其中,我覆盖了 ExecuteAsync 并希望使用存储在 Principal.Claims var 中的一些数据。但在调用 base.ExecuteAsync() 之前它是空的,而在调用它之后为时已晚。我没有看到任何其他可以覆盖的内容来帮助解决这个问题吗?

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;
    }
}

您可以覆盖 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);
    }

如果您需要访问控制器中的声明,您可以执行以下操作:

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 已设置。
  • 操作过滤器被调用。动作过滤器决定要么 让管道继续执行或终止管道。
  • 如果 Action Filters 没有终止请求,则注册 Action 检索调用程序。
  • 注册的Action Invoker的InvokeActionAsync方法是 调用以调用选定的操作方法。

注意:如果从执行Authorization Filters到执行action方法有任何异常发生,就会调用异常过滤器。

中间还发生了一些事情,但这非常接近完整视图。查看 ApiController source code 了解更多信息。

这对我有用 (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) 中注册的顺序是否重要,但我首先注册的是身份验证中间件。