Identityserver4 如何强制运行身份验证,以便主体可用于其他ASP.NET核心中间件?

Identityserver4 如何强制运行身份验证,以便主体可用于其他ASP.NET核心中间件?,identityserver4,Identityserver4,我正在尝试添加一个中间件,以便在基于客户端id的Web API中实现节流。此Web API受Identity Server 4和JWT身份验证处理程序的保护 问题是,当我的中间件运行时,Context.User.Claims总是空的。 我知道只有当请求点击Authorize属性时才会调用Jwt处理程序 因此,我的问题是,我如何“强制”Jwt处理程序在管道中更快地运行,以便我的中间件在令牌被验证并且客户端id声明在上下文主体中可用后获得调用 谢谢你能给我的任何帮助 设置Web API的代码如下所示

我正在尝试添加一个中间件,以便在基于客户端id的Web API中实现节流。此Web API受Identity Server 4和JWT身份验证处理程序的保护

问题是,当我的中间件运行时,Context.User.Claims总是空的。 我知道只有当请求点击Authorize属性时才会调用Jwt处理程序

因此,我的问题是,我如何“强制”Jwt处理程序在管道中更快地运行,以便我的中间件在令牌被验证并且客户端id声明在上下文主体中可用后获得调用

谢谢你能给我的任何帮助

设置Web API的代码如下所示:

public void ConfigureServices(IServiceCollection services)
{
    // Validation

    SmartGuard.NotNull(() => services, services);

    // Log

    this.Logger.LogTrace("Application services configuration starting.");

    // Configuration

    services
        .AddOptions()
        .Configure<ServiceConfiguration>(this.Configuration.GetSection(nameof(ServiceConfiguration)))
        .Configure<TelemetryConfiguration>(this.Configuration.GetSection(nameof(TelemetryConfiguration)))
        .Configure<TableStorageServiceConfiguration>(this.Configuration.GetSection(nameof(TableStorageServiceConfiguration)))
        .UseConfigurationSecrets();

    ServiceConfiguration serviceConfiguration = services.ResolveConfiguration<ServiceConfiguration>();

    // Telemetry (Application Insights)

    services.AddTelemetryForApplicationInsights();

    // Memory cache

    services.AddDistributedMemoryCache();

    // MVC

    services.AddMvc();

    // Identity

    services
        .AddAuthorization(
            (options) =>
            {
                options.AddPolicy(
                    Constants.Policies.Settings,
                    (policy) =>
                    {
                        policy.RequireClaim(Constants.ClaimTypes.Scope, Scopes.Settings);
                    });
            });

    // NOTE:
    // We are using the JWT Bearer handler here instead of the IdentityServer handler
    // because version 2.3.0 does not handle bearer challenges correctly.
    // For more info: https://github.com/IdentityServer/IdentityServer4/issues/2047
    // This is supposed to be fixed in version 2.4.0.

    services
        .AddAuthentication(Constants.AuthenticationSchemes.Bearer)
        .AddJwtBearer(
            (options) =>
            {
                options.Authority = serviceConfiguration.IdentityServerBaseUri;
                options.Audience = Constants.ApiName;
                options.RequireHttpsMetadata = false;
                options.IncludeErrorDetails = true;
                options.RefreshOnIssuerKeyNotFound = true;
                options.SaveToken = true;
                options.Events = new JwtBearerEvents()
                {
                    OnChallenge = HandleChallenge
                };
            });

    // Web API Versioning

    services.AddApiVersioning(
        (options) =>
        {
            options.DefaultApiVersion = new Microsoft.AspNetCore.Mvc.ApiVersion(ApiVersions.DefaultVersion.Major, ApiVersions.DefaultVersion.Minor);
            options.ReportApiVersions = true;
            options.AssumeDefaultVersionWhenUnspecified = true;
        });

    // Setup Throttling

    services
        .AddThrottling()
        .AddClientRateHandler(this.Configuration.GetSection(nameof(ClientRateThrottlingOptions)));

    // Routes analyzer
    // Creates the /routes route that lists all the routes configured

    services.AddRouteAnalyzerInDevelopment(this.CurrentEnvironment);

    // Add the managers

    services.AddManagers();

    // Background services

    services.AddBackgroundService<StorageSetupService>();

    // Log

    this.Logger.LogTrace("Application services configuration completed.");
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    // Validation

    SmartGuard.NotNull(() => app, app);
    SmartGuard.NotNull(() => env, env);

    // Log

    this.Logger.LogTrace("Application configuration starting.");

    // Error handling (Telemetry)

    app.UseTelemetryExceptionHandler();

    // Authentication

    app.UseAuthentication();

    // Register the throttling middleware

    app.UseThrottling();

    // MVC

    app.UseMvc(
        (routes) =>
        {
            // Routes analyzer

            routes.MapRouteAnalyzerInDevelopment(env);
        });

    // Log

    this.Logger.LogTrace("Application configuration completed.");
}
internal class ClientRateMiddleware : IClientRateThrottlingMiddleware
{
    public async Task InvokeAsync(HttpContext context, RequestDelegate next)
    {
        (...)
        Claim claim = context.User.FindFirst("client_id");
        // Claim is always null here because the Jwt handler has not run
        (...)
    }
}

好的,我想我已经破解了这个。我认为@Hugo Quintela Ribeiro关于授权的说法是正确的,只有当[Authorize]过滤器被点击时,或者在为整个应用程序设置授权的情况下,当不允许匿名的控制器被点击时,授权才会发生。这当然发生在控制器上,而不是中间件上

事实证明,您实际上可以强制在中间件中进行身份验证。我尝试了以下几种方法,但没有成功

await context.AuthenticateAsync();
await context.AuthenticateAsync("Custom"); //name of my jwt auth
最后,我必须注入IAuthorizationPolicyProvider和IPolicyEvaluator以获取默认策略并对其进行身份验证

using cpDataORM;
using cpDataServices.Services;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Authorization.Policy;
using Microsoft.AspNetCore.Http;
using System.Globalization;
using System.Threading.Tasks;

namespace cpDataASP.Middleware
{
    public class LocalizationAndCurrencyMiddleware
    {
        private readonly RequestDelegate _next;

        public LocalizationAndCurrencyMiddleware(RequestDelegate next)
        {
            _next = next;
        }



        public async Task Invoke(HttpContext context, IUserService _userService, ILoginContextAccessor loginContext, IAuthorizationPolicyProvider policyProvider, IPolicyEvaluator policyEvaluator)
        {
            var policy = await policyProvider.GetDefaultPolicyAsync();
            await policyEvaluator.AuthenticateAsync(policy, context);
            var localizationResources = await _userService.GetLocalizationResources();
            loginContext.Timezone = localizationResources.Timezone;
            CultureInfo.CurrentCulture = localizationResources.Culture;

            await _next.Invoke(context);
        }
    }
}

您的API设置在我看来很好,我希望在Jwt处理程序到达中间件时调用它,并填充用户/声明。承载令牌是否可能丢失或无效?您可以尝试挂接到JWTBeareEvents(消息已接收,令牌已验证)以跟踪正在发生的事情。我确信Jwt处理程序仅在命中[Authorize]筛选器时执行。我能够实现一个资源过滤器,它实现了我想要的,因为它在authorize过滤器之后运行。这种方法的问题是,它在请求处理中运行得很晚。对于节流组件,它应该尽快运行。这很奇怪-在一个简化的示例中,我很难重现这种行为。如果我将默认方案设置为“Bearer”,并在请求中发送一个有效的jwt,那么用户和声明可用于管道中的下一个中间件。您的
ConfigureServices()
方法中还发生了什么?@Peter,我已经更新了问题,将ConfigureServices()和Configure()中的所有代码都包括在内。您在哪里可以解决这个问题?