ASPNET CORE InvalidOperationException:无法重定向到授权端点,配置可能丢失或无效
ASPNET CORE InvalidOperationException: Cannot redirect to the authorization endpoint, the configuration may be missing or invalid
我收到错误 InvalidOperationException:无法重定向到授权端点,配置可能丢失或无效。
在此之前,我遇到了类似“权限、元地址、配置或配置管理器丢失”之类的错误。我觉得这很重要。所以,我有:
/// <summary>
/// Configures OpenID Connect authentication.
/// </summary>
/// <param name="builder">The <see cref="IPersonalIdentityServerBuilder"/> object.</param>
/// <returns>The <see cref="IPersonalIdentityServerBuilder"/>.</returns>
public static IPersonalIdentityServerBuilder AddOpenIdConnectAuthentication(this IPersonalIdentityServerBuilder builder)
{
IServiceCollection _services = builder?.Services ?? throw new ArgumentNullException(nameof(builder));
_services
.AddAuthentication(opt => opt.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme)
.AddOpenIdConnect();
_services.AddSingleton<IPostConfigureOptions<OpenIdConnectOptions>, ConfigureOpenIdConnectOptions>();
return builder;
}
然后我有以下 class 配置选项
/// <summary>
/// Configuration class for the <see cref="OpenIdConnectOptions"/>.
/// </summary>
internal class ConfigureOpenIdConnectOptions :
IPostConfigureOptions<OpenIdConnectOptions>
{
/// <summary>
/// My personal OpenId options.
/// </summary>
private readonly IOptions<PersonalIentityServerOpenIdOptions> _openIdOptions;
/// <summary>
/// The class that has the events for OpenId authentication.
/// </summary>
private readonly OpenIdNotificationEventHandler _eventHandler;
/// <summary>
/// Initializes a new instance of the <see cref="ConfigureOpenIdConnectOptions"/> class.
/// </summary>
/// <param name="openIdOptions">The personal OpenId options.</param>
/// <param name="eventHandler">The handler for OpenId authentication events.</param>
public ConfigureOpenIdConnectOptions(
IOptions<PersonalIdentityServerOpenIdOptions> openIdOptions,
OpenIdNotificationEventHandler eventHandler)
{
this._openIdOptions = openIdOptions ?? throw new ArgumentNullException(nameof(openIdOptions));
this._eventHandler = eventHandler ?? throw new ArgumentNullException(nameof(eventHandler));
}
/// <summary>
/// Configures the options.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="options">The options to configure.</param>
public void PostConfigure(string name, OpenIdConnectOptions options)
{
PersonalIdentityServerOpenIdOptions _opt = this._openIdOptions.Value;
options.Authority = _opt.Authority;
options.ClientId = _opt.ClientId;
options.ClientSecret = _opt.Secret;
options.MetadataAddress = "/" + ProtocolPath.Discovery;
options.ProtocolValidator.RequireNonce = true;
options.ResponseType = OpenIdConnectResponseType.Code;
options.UsePkce = true;
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = JwtClaimTypes.Name,
RoleClaimType = JwtClaimTypes.Role,
};
// Keeps id_token smaller
options.GetClaimsFromUserInfoEndpoint = true;
// The callback paths require a relative URL. This was a change that Microsoft made in the .NET Core version. We, however,
// support an absolute URL. Attempting to set the callback paths to an absolute URL will cause an exception to be thrown.
// Therefore, we will now support either. If it's an absolute URL then it gets set in the RedirectToIdentityProvider
// event. If it's a relative URL, we'll set it here.
if (!_opt.SetLowLevelRedirectUri) { options.CallbackPath = _opt.RedirectUri; }
if (!_opt.SetLowLevelPostLogoutRedirectUri) { options.SignedOutCallbackPath = _opt.PostLogoutRedirectUri; }
_opt.Scopes.ForEach(s => options.Scope.Add(s));
options.Events = new OpenIdConnectEvents
{
OnAuthorizationCodeReceived = this._eventHandler.AuthorizationCodeRecieved,
OnTokenResponseReceived = this._eventHandler.TokenResponseReceived,
OnTokenValidated = this._eventHandler.TokenValidated,
OnRedirectToIdentityProvider = this._eventHandler.RedirectToIdentityProvider,
};
}
}
经过多次反编译和 Google 搜索,我最终将以下行添加到上面定义的 AddOpenIdConnectAuthentication 方法中。这是微软对开放ID设置的配置。
_services.AddSingleton<IPostConfigureOptions<OpenIdConnectOptions>, OpenIdConnectPostConfigureOptions>();
这解决了那个问题,但现在我有了标题中的那个。从源头上看,好像是因为 IssuerAddress 是空的。对于我的生活,我不明白为什么。此外,我不明白为什么我需要添加 Microsoft 自己的配置 class 才能使其正常工作。
我知道我可以以某种方式绕过它并且可能会找到解决方法,但我认为它不应该这么难。
如果有人有任何想法,我们将非常欢迎。
更新
我想扩展我发现的一些东西,但由于我花在这上面的时间而最终改变了。我想特别感谢下面的https://whosebug.com/users/68490/tore-nestenius。
我最终从使用 IPostConfigure<OpenIdConnectOptions>
更改为 IConfigure<OpenIdConnectOptions>
。这样做时,它似乎通过 IConfigureNamedOptions<OpenIdConnectOptions>
的 Configure(name, options)
而不是 IConfigureOptions<OpenIdConnectOptions>
的 Configure(options)
。因此,我同时实施了两者。我不知道你是否必须这样做,因为我没有尝试所有可能的组合,但这样做有效。
使用 IPostConfigurationOptions<OpenIdConnectOptions>
时,您 必须 在调用 AddOpenIdConnect()
.
之前将其添加到服务 collection
我还删除了手动注册 Microsoft 的行 IPostConfigreOptions
,不需要这个。
元数据地址应该是以 https:// 开头的绝对地址,而不是像您的代码中那样的相对 URL:
options.MetadataAddress = "/" + ProtocolPath.Discovery;
那么我有点困惑为什么你需要添加你自己的 ConfigureOpenIdConnectOptions class?要配置 openid-connect,我只需:
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
}).AddCookie(options =>
{
options.LoginPath = "/User/Login";
options.LogoutPath = "/User/Logout";
options.AccessDeniedPath = "/User/AccessDenied";
}).AddMyTestOpenIdConnect(options =>
{
options.Authority = "https://localhost:6001";
options.ClientId = "authcodeflowclient";
options.ClientSecret = "mysecret";
options.ResponseType = "code";
...
});
如果元数据 URL 在 HTTP 上,您可能需要设置
options.RequireHttpsMetadata = false;
但是如果您设置了 Authority 字段,那么我怀疑您还需要设置 MetaDataAddress。
我收到错误 InvalidOperationException:无法重定向到授权端点,配置可能丢失或无效。
在此之前,我遇到了类似“权限、元地址、配置或配置管理器丢失”之类的错误。我觉得这很重要。所以,我有:
/// <summary>
/// Configures OpenID Connect authentication.
/// </summary>
/// <param name="builder">The <see cref="IPersonalIdentityServerBuilder"/> object.</param>
/// <returns>The <see cref="IPersonalIdentityServerBuilder"/>.</returns>
public static IPersonalIdentityServerBuilder AddOpenIdConnectAuthentication(this IPersonalIdentityServerBuilder builder)
{
IServiceCollection _services = builder?.Services ?? throw new ArgumentNullException(nameof(builder));
_services
.AddAuthentication(opt => opt.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme)
.AddOpenIdConnect();
_services.AddSingleton<IPostConfigureOptions<OpenIdConnectOptions>, ConfigureOpenIdConnectOptions>();
return builder;
}
然后我有以下 class 配置选项
/// <summary>
/// Configuration class for the <see cref="OpenIdConnectOptions"/>.
/// </summary>
internal class ConfigureOpenIdConnectOptions :
IPostConfigureOptions<OpenIdConnectOptions>
{
/// <summary>
/// My personal OpenId options.
/// </summary>
private readonly IOptions<PersonalIentityServerOpenIdOptions> _openIdOptions;
/// <summary>
/// The class that has the events for OpenId authentication.
/// </summary>
private readonly OpenIdNotificationEventHandler _eventHandler;
/// <summary>
/// Initializes a new instance of the <see cref="ConfigureOpenIdConnectOptions"/> class.
/// </summary>
/// <param name="openIdOptions">The personal OpenId options.</param>
/// <param name="eventHandler">The handler for OpenId authentication events.</param>
public ConfigureOpenIdConnectOptions(
IOptions<PersonalIdentityServerOpenIdOptions> openIdOptions,
OpenIdNotificationEventHandler eventHandler)
{
this._openIdOptions = openIdOptions ?? throw new ArgumentNullException(nameof(openIdOptions));
this._eventHandler = eventHandler ?? throw new ArgumentNullException(nameof(eventHandler));
}
/// <summary>
/// Configures the options.
/// </summary>
/// <param name="name">The name.</param>
/// <param name="options">The options to configure.</param>
public void PostConfigure(string name, OpenIdConnectOptions options)
{
PersonalIdentityServerOpenIdOptions _opt = this._openIdOptions.Value;
options.Authority = _opt.Authority;
options.ClientId = _opt.ClientId;
options.ClientSecret = _opt.Secret;
options.MetadataAddress = "/" + ProtocolPath.Discovery;
options.ProtocolValidator.RequireNonce = true;
options.ResponseType = OpenIdConnectResponseType.Code;
options.UsePkce = true;
options.TokenValidationParameters = new TokenValidationParameters
{
NameClaimType = JwtClaimTypes.Name,
RoleClaimType = JwtClaimTypes.Role,
};
// Keeps id_token smaller
options.GetClaimsFromUserInfoEndpoint = true;
// The callback paths require a relative URL. This was a change that Microsoft made in the .NET Core version. We, however,
// support an absolute URL. Attempting to set the callback paths to an absolute URL will cause an exception to be thrown.
// Therefore, we will now support either. If it's an absolute URL then it gets set in the RedirectToIdentityProvider
// event. If it's a relative URL, we'll set it here.
if (!_opt.SetLowLevelRedirectUri) { options.CallbackPath = _opt.RedirectUri; }
if (!_opt.SetLowLevelPostLogoutRedirectUri) { options.SignedOutCallbackPath = _opt.PostLogoutRedirectUri; }
_opt.Scopes.ForEach(s => options.Scope.Add(s));
options.Events = new OpenIdConnectEvents
{
OnAuthorizationCodeReceived = this._eventHandler.AuthorizationCodeRecieved,
OnTokenResponseReceived = this._eventHandler.TokenResponseReceived,
OnTokenValidated = this._eventHandler.TokenValidated,
OnRedirectToIdentityProvider = this._eventHandler.RedirectToIdentityProvider,
};
}
}
经过多次反编译和 Google 搜索,我最终将以下行添加到上面定义的 AddOpenIdConnectAuthentication 方法中。这是微软对开放ID设置的配置。
_services.AddSingleton<IPostConfigureOptions<OpenIdConnectOptions>, OpenIdConnectPostConfigureOptions>();
这解决了那个问题,但现在我有了标题中的那个。从源头上看,好像是因为 IssuerAddress 是空的。对于我的生活,我不明白为什么。此外,我不明白为什么我需要添加 Microsoft 自己的配置 class 才能使其正常工作。
我知道我可以以某种方式绕过它并且可能会找到解决方法,但我认为它不应该这么难。
如果有人有任何想法,我们将非常欢迎。
更新
我想扩展我发现的一些东西,但由于我花在这上面的时间而最终改变了。我想特别感谢下面的https://whosebug.com/users/68490/tore-nestenius。
我最终从使用 IPostConfigure<OpenIdConnectOptions>
更改为 IConfigure<OpenIdConnectOptions>
。这样做时,它似乎通过 IConfigureNamedOptions<OpenIdConnectOptions>
的 Configure(name, options)
而不是 IConfigureOptions<OpenIdConnectOptions>
的 Configure(options)
。因此,我同时实施了两者。我不知道你是否必须这样做,因为我没有尝试所有可能的组合,但这样做有效。
使用 IPostConfigurationOptions<OpenIdConnectOptions>
时,您 必须 在调用 AddOpenIdConnect()
.
我还删除了手动注册 Microsoft 的行 IPostConfigreOptions
,不需要这个。
元数据地址应该是以 https:// 开头的绝对地址,而不是像您的代码中那样的相对 URL:
options.MetadataAddress = "/" + ProtocolPath.Discovery;
那么我有点困惑为什么你需要添加你自己的 ConfigureOpenIdConnectOptions class?要配置 openid-connect,我只需:
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
}).AddCookie(options =>
{
options.LoginPath = "/User/Login";
options.LogoutPath = "/User/Logout";
options.AccessDeniedPath = "/User/AccessDenied";
}).AddMyTestOpenIdConnect(options =>
{
options.Authority = "https://localhost:6001";
options.ClientId = "authcodeflowclient";
options.ClientSecret = "mysecret";
options.ResponseType = "code";
...
});
如果元数据 URL 在 HTTP 上,您可能需要设置
options.RequireHttpsMetadata = false;
但是如果您设置了 Authority 字段,那么我怀疑您还需要设置 MetaDataAddress。