我有一个 Jwt 持有者令牌,我将其存储在 .Net Core 2.1 应用程序的 Session 中。在我的中间件中,我通过以下方式拦截请求并将令牌附加到标头:
httpContext.Request.Headers.Add("Authorization", $"Bearer {token}");
这目前不起作用,因为我在受保护的路由上收到未经授权的信息。如果我使用邮递员进行相同的调用并在标头中传递授权和持有者令牌,它可以工作。
我需要对 http 进行哪些更改。要求使其被接受?
使用 JWT 启动的部分: var 签名密钥 = 密钥;
services.AddSingleton<IJwtFactory, JwtFactory>();
var jwtAppSettingOptions = Configuration.GetSection(nameof(JwtIssuerOptions));
// Configure JwtIssuerOptions
services.Configure<JwtIssuerOptions>(options =>
{
options.Issuer = Issuer;
options.Audience = Audience;
options.SigningCredentials = new SigningCredentials(signingKey, SecurityAlgorithms.HmacSha256);
});
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidIssuer = Issuer,
ValidateAudience = true,
ValidAudience = Audience,
ValidateIssuerSigningKey = true,
IssuerSigningKey = signingKey,
RequireExpirationTime = false,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
})
.AddCookie(cfg => cfg.SlidingExpiration = true);
配置:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, IServiceProvider serviceProvider)
{
app.UseAuthentication();
app.UseStaticFiles();
app.UseSession();
app.UseHttpContextLogging();
app.ConfigureErrorHandling(env);
app.UseSiteRouteMiddleware(getRoutes); -- Middleware that intercepts the request, adding the token here
app.UseRequestLocalization();
app.UseRewriter();
app.UseMvc(getRoutes);
}
app.UseAuthentication();
这就是注册身份验证中间件的原因,该中间件最终将在传入的 HTTP 请求中查找 JWT 持有者令牌,并将使用它根据该值对用户进行身份验证。
由于该中间件是您注册的第一个中间件,因此在管道中的其他任何内容运行之前,它也将作为第一个中间件运行。由于app.UseSiteRouteMiddleware()
调用稍后出现,因此将修改传入 HTTP 请求的自定义中间件也将稍后运行。因此,它将在请求已用于身份验证目的后对其进行修改。
如果您希望在有机会重写 HTTP 请求后进行身份验证,则必须在app.UseAuthentication()
调用之前移动app.UseSiteRouteMiddleware()
。
但请注意,由于自定义中间件使用会话,因此会话中间件也必须在自定义中间件之前运行。毕竟,您的流的工作方式应该是这样的:
- 检索会话信息(会话中间件(
- 调整 HTTP 请求标头(站点路由中间件(
- 对用户进行身份验证(身份验证中间件(
因此,您必须按此顺序设置这三个中间件:
app.UseSession();
app.UseSiteRouteMiddleware(getRoutes);
app.UseAuthentication();
话虽如此,您存储 JWT 的方法相当不成熟。使用持有者令牌的身份验证通常应该是无状态的,因为客户端显式传递对用户进行身份验证所需的令牌。这与常见的基于 Cookie 的身份验证形成对比,在 Cookie 中,数据作为请求的一部分隐式通过 Cookie 传递。
具有讽刺意味的是,您使用会话中间件来存储 JWT 持有者令牌实际上正是这样做的:默认情况下,会话中间件使用会话cookie来恢复以前的用户会话。因此,在您的解决方案中,您基本上最终使用不同的 cookie来启用身份验证。
除非您有充分的理由进行此设计,否则我强烈建议您切换到标准cookie身份验证,该身份验证仅将身份存储在cookie中,而不是将其存储在JSON Web令牌中。这通常也会降低身份验证设置的复杂性,同时使其得到更好的支持。同时,您还将失去使用其他会话管理的要求,这通常是建议不要使用的(同样,除非您有充分的理由(。
如果您需要"普通"JWT 持有者身份验证,例如,如果您的应用程序也由 API 客户端访问,请注意,在您的应用程序中同时使用 JWT 持有者身份验证和cookie 身份验证并没有错。这样,您可以自由选择最适合每种情况的身份验证样式。
正如评论中所发布的那样,在调用UseSiteRouteMiddleware
时,身份验证中间件已经处理完毕。
所以设置任何东西都晚了。更改中间件的执行顺序。 在UseAuthentcation()
之前,将您的UseSiteRouteMiddleware
更接近开头。
根据官方文档,注册顺序决定了中间件的执行顺序。
在
Startup.Configure
方法中添加中间件组件的顺序定义了在请求中调用中间件组件的顺序以及响应的相反顺序。顺序对于安全性、性能和功能至关重要。