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:如何在资源服务器中注册签名密钥以验证令牌?