【发布时间】:2020-07-23 12:31:28
【问题描述】:
我使用 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;
}
}
};
这一切都很完美,除了服务启动后的第一次调用。需要明确的是,除了第一个电话外,每个电话都完全按照我的意愿工作。 (它将令牌放入并更新 User 对象,就像我需要的那样。)
但是对于第一次调用,OnMessageReceived 没有被击中。并且我的控制器中的User 对象没有设置。
我检查了HttpContext 的第一次调用,并且“X-JWT-Assertion”标头位于Request.Headers 列表中(其中包含 JWT)。但是,出于某种原因,没有调用 OnMessageReceived 事件。
我怎样才能让OnMessageReceived 被调用来为我的服务首次调用服务操作?
重要提示:我发现问题出在AddJwtBearer 中的async await。 (请参阅下面的答案。)这就是我真正想要的这个问题。
但是,由于无法取消赏金,我仍然会将赏金奖励给任何能够展示使用AddJwtBearer 和async await 的方法的人,它正在等待实际的HttpClient 调用。或者显示为什么 async await 不应该与 AddJwtBearer 一起使用的文档。
【问题讨论】:
-
我已将此事件处理程序放入 bolierplate WebAPI 模板 - 似乎从第一个请求中提取处理程序。会不会是您的中间件订单在某种程度上影响了它?
-
@timur - 在我的问题末尾查看我的更新。 (这是由于
asyncawait无法很好地与调用管道配合使用。) -
似乎
AddJwtBearer(和底层的AuthenticationBuilder.AddSchemeHelper)不期望在那里进行异步调用 - 它只是将 IConfigureOptions 添加到服务中。另一方面,@ 987654346@ - 正在等待中。所以我想知道你是否可以让OnMessageReceivedlambda 异步,将你的 http 调用移动到OnMessageReceived正文并以某种方式将结果缓存在那里? -
@Vaccano 你有没有想出一个好的解决方案来解决实际的原始问题?好吧,@timur 的解决方案可能适用于您的情况,但不适用于我的情况。我需要将
options.Authority设置为异步获得的值,但我想不出比options.Authority = Task.Run(() => ...).GetAwaiter().GetResult()更好的值,但我想尽可能避免将异步代码包装在同步代码中。不过我希望不会。 -
@jsabrooke - 是的,我做到了。我能够使用依赖注入让它工作。这样我就可以提前设置我需要的东西。要让它工作,你需要像这样注册一个
IConfigureOptions:services.AddTransient<IConfigureOptions<JwtBearerOptions>, ConfigureJwtBearerOptions>();然后创建一个继承自IConfigureNamedOptions<JwtBearerOptions>的类(在这种情况下称为ConfigureJwtBearerOptions)。该类将用于设置 JwtBearerOptions 并将支持依赖注入。这是一个例子:stackoverflow.com/q/61186836/16241
标签: c# asp.net-core .net-core asp.net-core-3.1