OpenIddict 缺少强制性的“code_challenge”参数

Posted

技术标签:

【中文标题】OpenIddict 缺少强制性的“code_challenge”参数【英文标题】:The mandatory 'code_challenge' parameter is missing with OpenIddict 【发布时间】:2022-01-05 11:02:09 【问题描述】:

我有一个运行 asp.net core 5 和 openiddict 3.1.1 的身份服务器 我在从 openiddict 收到错误的地方遇到问题:

错误:invalid_request error_description:缺少必需的“code_challenge”参数。 error_uri:https://documentation.openiddict.com/errors/ID2029

在某些情况下,但不是全部。我的身份服务器的 startup.cs 为:

services.AddDbContext<IdentityContext>(options =>
        
            options.UseSqlServer(dbConnectionString, x => x.UseNetTopologySuite());
            // Register the entity sets needed by OpenIddict.
            // Note: use the generic overload if you need
            // to replace the default OpenIddict entities.
            options.UseOpenIddict<Guid>();
        );

        services.AddTransient<IPasswordHasher<ApplicationUser>, CustomPasswordHasher>();
        services.AddTransient<IOptions<IdentityOptions>, CustomOptions>();
        services.AddScoped<SignInManager<ApplicationUser>, CustomSignInManager>();

        services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<IdentityContext>()
                //.AddDefaultUI()
                .AddDefaultTokenProviders();


        services.AddOpenIddict()

    // Register the OpenIddict core components.
    .AddCore(options =>
    
        // Configure OpenIddict to use the Entity Framework Core stores and models.
        // Note: call ReplaceDefaultEntities() to replace the default entities.
        options.UseEntityFrameworkCore()
               .UseDbContext<IdentityContext>()
               .ReplaceDefaultEntities<Guid>();
    )

    // Register the OpenIddict server components.
    .AddServer(options =>
    
        // Enable the authorization, device, logout, token, userinfo and verification endpoints.
        options.SetAuthorizationEndpointUris("/connect/authorize")
               .SetLogoutEndpointUris("/connect/signout")
               .SetTokenEndpointUris("/connect/token");

        // Enable the client credentials flow.
        options
        .AllowAuthorizationCodeFlow().RequireProofKeyForCodeExchange()
        .AllowRefreshTokenFlow();

        // Encryption and signing of tokens
        options
            .AddEphemeralEncryptionKey()
            .AddEphemeralSigningKey()
            .DisableAccessTokenEncryption();    //TODO: not a huge deal as long as we're not hiding anything bad here.

        // Expose all the supported claims in the discovery document.
        options.RegisterClaims(Configuration.GetSection("OpenIddict:Claims").Get<string[]>());

        // Expose all the supported scopes in the discovery document.
        options.RegisterScopes(Configuration.GetSection("OpenIddict:Scopes").Get<string[]>());

        // Register the ASP.NET Core host and configure the ASP.NET Core-specific options.
        options.UseAspNetCore()
               .EnableStatusCodePagesIntegration()
               .EnableAuthorizationEndpointPassthrough()
                .EnableAuthorizationRequestCaching()
               .EnableLogoutEndpointPassthrough()
               .EnableVerificationEndpointPassthrough()
               .EnableTokenEndpointPassthrough();
    )

    // Register the OpenIddict validation components.
    .AddValidation(options =>
    
        // Import the configuration from the local OpenIddict server instance.
        options.UseLocalServer();

        // Register the ASP.NET Core host.
        options.UseAspNetCore();

        // Enable authorization entry validation, which is required to be able
        // to reject access tokens retrieved from a revoked authorization code.
        options.EnableAuthorizationEntryValidation();
    );

具有以下 OpenIDWorker:

public async Task StartAsync(CancellationToken cancellationToken)
    
        using IServiceScope scope = _serviceProvider.CreateScope();

        IdentityContext context = scope.ServiceProvider.GetRequiredService<IdentityContext>();

        await RegisterApplicationsAsync(scope.ServiceProvider, _configuration);

        static async Task RegisterApplicationsAsync(IServiceProvider provider, IConfiguration configuration)
        
            IOpenIddictApplicationManager manager = provider.GetRequiredService<IOpenIddictApplicationManager>();
            string clientID = configuration.GetSection("OpenIddict:ClientId").Get<string>();

            string clientSecretString = "blahblahblah";
            if (await manager.FindByClientIdAsync(clientID) is null)
            
                await manager.CreateAsync(new OpenIddictApplicationDescriptor
                
                    ClientId = clientID,
                    ClientSecret = clientSecretString,
                    ConsentType = ConsentTypes.Explicit,
                    DisplayName = configuration.GetSection("OpenIddict:DisplayName").Get<string>(),
                    PostLogoutRedirectUris =

    new Uri("https://localhost:44330/signout-callback-oidc")
,
                    RedirectUris =

    new Uri("https://localhost:44330/signin-oidc")
,
                    Permissions =
                
                    Permissions.Endpoints.Authorization,
                    Permissions.Endpoints.Logout,
                    Permissions.Endpoints.Token,
                    Permissions.GrantTypes.AuthorizationCode,
                    Permissions.GrantTypes.RefreshToken,
                    Permissions.ResponseTypes.Code,
                    Permissions.Scopes.Email,
                    Permissions.Scopes.Profile,
                    Permissions.Scopes.Roles,
                ,
                    Requirements =
                
                    Requirements.Features.ProofKeyForCodeExchange
                
                );
            
        

    

当我尝试使用具有以下 startup.cs 的 C# razor 应用程序连接到服务器时,它工作正常并且没有任何问题:

string clientSecretString = "blahblahblah";
        services.AddAuthentication(options =>
        
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
        ).AddCookie(CookieAuthenticationDefaults.AuthenticationScheme, options =>
         
             options.LoginPath = "/login";
             options.ExpireTimeSpan = TimeSpan.FromMinutes(50);
             options.SlidingExpiration = false;
         )

        .AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
        
            // Note: these settings must match the application details
            // inserted in the database at the server level.
            options.ClientId = Configuration.GetSection("ClientId").Get<string>();
            options.ClientSecret = clientSecretString;

            options.RequireHttpsMetadata = false;
            options.GetClaimsFromUserInfoEndpoint = true;
            options.SaveTokens = true;

            // Use the authorization code flow.
            options.ResponseType = OpenIdConnectResponseType.Code;
            options.AuthenticationMethod = OpenIdConnectRedirectBehavior.RedirectGet;

            // Note: setting the Authority allows the OIDC client middleware to automatically
            // retrieve the identity provider's configuration and spare you from setting
            // the different endpoints URIs or the token validation parameters explicitly.

            options.Authority = "https://localhost:44330/";

            options.Scope.Add("email");
            options.Scope.Add("roles");
            options.Scope.Add("offline_access");

            options.SecurityTokenValidator = new JwtSecurityTokenHandler
            
                // Disable the built-in JWT claims mapping feature.
                InboundClaimTypeMap = new Dictionary<string, string>()
            ;

            options.TokenValidationParameters.NameClaimType = "name";
            options.TokenValidationParameters.RoleClaimType = "role";

            options.AccessDeniedPath = "/";
        );

但是当我尝试使用 https://oidcdebugger.com/ 连接到它时,或者如果我尝试使用 Azure B2C 用户流连接到它,我会收到上面关于缺少 code_challenge 的错误消息(参见图片 )

我在这里缺少什么?我的计划是使用 B2C,但我没有看到是什么阻碍了我。

【问题讨论】:

【参考方案1】:

请参阅https://github.com/openiddict/openiddict-core/issues/1361 以供参考。问题最终成为 B2C 本身的问题,需要对其进行修复

【讨论】:

以上是关于OpenIddict 缺少强制性的“code_challenge”参数的主要内容,如果未能解决你的问题,请参考以下文章

OpenIddict:当两个或更多服务实例计数时出现 401 错误

带有 ClientCredentials 流的 OpenIdDict 降级模式

OpenIddict:如何在资源服务器中注册签名密钥以验证令牌?

OpenIddict 的临时关键问题

.NET 4.6 中的 OpenIddict 3 不可用令牌验证

ASP.NET 4.5 或替代框架中的 OpenIdDict?