首次操作调用未调用 JwtBearerEvents.OnMessageReceived

Vac*_*ano 8 c# .net-core asp.net-core asp.net-core-3.1

我使用 WSO2 作为我的身份提供者 (IDP)。它将 JWT 放在名为“X-JWT-Assertion”的标头中。

为了将其提供给 ASP.NET Core 系统,我添加了一个OnMessageReceived事件。这允许我将 设置token为标题中提供的值。

这是我必须执行的代码(关键部分是非括号代码的最后 3 行):

services.AddAuthentication(options =>
{
    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
    options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie()
.AddJwtBearer(async options =>
{
    options.TokenValidationParameters = 
         await wso2Actions.JwtOperations.GetTokenValidationParameters();

    options.Events = new JwtBearerEvents()
    {
        // WSO2 sends the JWT in a different field than what is expected.
        // This allows us to feed it in.
        OnMessageReceived = context =>
        {
            context.Token = context.HttpContext.Request.Headers["X-JWT-Assertion"];
            return Task.CompletedTask;
        }
    }
};
Run Code Online (Sandbox Code Playgroud)

除了服务启动后的第一次调用外,这一切都完美无缺。需要明确的是,除了第一个调用之外,每个调用都完全按照我的意愿工作。(它把令牌放入并更新User我需要的对象。)

但是对于第一次调用,OnMessageReceived没有命中。并且User我的控制器中的对象没有设置。

我检查HttpContext了第一个调用,并且“X-JWT-Assertion”标头在Request.Headers列表中(其中包含 JWT)。但是,出于某种原因,该OnMessageReceived事件并没有被要求。

如何OnMessageReceived在第一次调用我的服务的服务操作时被调用?

重要提示:我发现问题出async awaitAddJwtBearer. (见下面我的回答。)这就是我真正想从这个问题中得到的。

然而,由于赏金不能cancled,我仍然会奖励赏金的人谁可以显示的方式,使用AddJwtBearerasync await它正在等待一个实际的HttpClient通话。或显示为什么async await不应该与AddJwtBearer.

Vac*_*ano 6

更新:
lambda 是一种Action方法。它不返回任何东西。因此,尝试在其中实现异步是不可能的,除非它被火和遗忘。

此外,该方法在第一次调用时被调用。所以答案是提前在这个方法中调用你需要的任何东西并缓存它。(但是,我还没有想出一种使用依赖注入项进行此调用的非 hack 方法。)然后在第一次调用期间,将调用此 lambda。那时你应该从缓存中提取你需要的值(因此不会减慢第一次调用的速度)。


这是我最后想出来的。

lambda forAddJwtBearer不适用于async await. 我的呼叫await wso2Actions.JwtOperations.GetTokenValidationParameters();等待很好,但呼叫管道继续进行而无需等待AddJwtBearer完成。

随着async await呼叫顺序是这样的:

  1. 服务启动(你等待一段时间让一切都开心。)
  2. 向服务发出呼叫。
  3. AddJwtBearer 叫做。
  4. await wso2Actions.JwtOperations.GetTokenValidationParameters(); 叫做。
  5. GetTokenValidationParameters()调用HttpClientwith await
  6. HttpClient做一个期待已久的调用来获取发行人的公开签名密钥。
  7. HttpClient等待时,原始调用的其余部分会通过。尚未设置任何事件,因此它只是像往常一样继续调用管道。
    • 这是它“似乎跳过”OnMessageReceived事件的地方。
  8. HttpClient获取与公共密钥的响应。
  9. 执行AddJwtBearer继续。
  10. OnMessageReceived事件是设置。
  11. 对服务进行第二次调用
  12. 因为事件最终被设置,所以事件被调用。(AddJwtBearer仅在第一次调用时调用。)

因此,当等待发生时(在这种情况下,它最终会调用 HttpClient 以获取颁发者签名密钥),第一个调用的其余部分会通过。因为还没有事件设置,它不知道调用处理程序。

我将 lambda 更改AddJwtBearer为不是异步的,它工作得很好。

注意:
这里有两件事看起来很奇怪:

  1. 我原以为AddJwtBearer会在启动时调用,而不是在第一次调用服务时调用。
  2. 如果无法正确应用等待,我会认为它AddJwtBearer不支持asynclambda 签名。

我不确定这是否是一个错误,但我将其作为一个发布以防万一:https : //github.com/dotnet/aspnetcore/issues/20799