Asp.net core ASPNET CORE InvalidOperationException:无法重定向到授权端点,配置可能丢失或无效

Asp.net core ASPNET CORE InvalidOperationException:无法重定向到授权端点,配置可能丢失或无效,asp.net-core,openid,Asp.net Core,Openid,我收到错误InvalidOperationException:无法重定向到授权端点,配置可能丢失或无效 在此之前,我有一个错误,上面写着“缺少权限、元地址、配置或配置管理器”。我觉得这很重要。所以,我所拥有的: /// <summary> /// Configures OpenID Connect authentication. /// </summary> /// <param name="

我收到错误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;
        }
//
///配置OpenID连接身份验证。
/// 
///物体。
///这个。
公共静态IPersonalIdentityServerBuilder AddOpenIdConnectAuthentication(此IPersonalIdentityServerBuilder)
{
IServiceCollection_services=builder?.services??抛出新的ArgumentNullException(nameof(builder));
_服务
.AddAuthentication(opt=>opt.DefaultChallengeScheme=OpenIdConnectDefaults.AuthenticationScheme)
.AddOpenIdConnect();
_services.AddSingleton();
返回生成器;
}
然后我有一个配置选项的类

/// <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,
        };
    }
}
//
///的配置类。
/// 
内部类配置OpenIDConnectOptions:
IPostConfigureOptions
{
/// 
///我的个人OpenId选项。
/// 
私有只读选项_openIdOptions;
/// 
///具有OpenId身份验证事件的类。
/// 
私有只读OpenIdNotificationEventHandler\u eventHandler;
/// 
///初始化类的新实例。
/// 
///个人OpenId选项。
///OpenId身份验证事件的处理程序。
公共配置OpenIDConnectOptions(
IOptions openIdOptions,
OpenIdNotificationEventHandler(事件处理程序)
{
这._openIdOptions=openIdOptions??抛出新的ArgumentNullException(nameof(openIdOptions));
这._eventHandler=eventHandler??抛出新的ArgumentNullException(nameof(eventHandler));
}
/// 
///配置选项。
/// 
///名字。
///要配置的选项。
public void PostConfigure(字符串名称、OpenIdConnectOptions选项)
{
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=新的TokenValidationParameters
{
NameClaimType=JwtClaimTypes.Name,
RoleClaimType=JwtClaimTypes.Role,
};
//使id_令牌更小
options.GetClaimsFromUserInfoEndpoint=true;
//回调路径需要相对URL。这是Microsoft在.NET核心版本中所做的更改。但是,
//支持绝对URL。尝试将回调路径设置为绝对URL将导致引发异常。
//因此,我们现在将支持其中一种。如果它是一个绝对URL,那么它将在RedirectToIdentityProvider中设置
//如果它是一个相对URL,我们将在这里设置它。
如果(!\u opt.SetLowLevelRedirectUri){options.CallbackPath=\u opt.RedirectUri;}
如果(!\u opt.setLowLevel PostLogoutRedectUri){options.SignedOutCallbackPath=\u opt.PostLogoutRedectUri;}
_opt.Scopes.ForEach(s=>options.Scope.Add);
options.Events=新的OpenIdConnectEvents
{
OnAuthorizationCodeReceived=此。\u eventHandler.AuthorizationCodeReceived,
OnTokenResponseReceived=this.\u eventHandler.TokenResponseReceived,
OnTokenValidated=this.\u eventHandler.TokenValidated,
OnRedirectToIdentityProvider=此。\u eventHandler.RedirectToIdentityProvider,
};
}
}
经过大量的反编译和谷歌搜索,我最终在上面定义的AddOpenIdConnectAuthentication方法中添加了以下内容。这是Microsofts针对开放ID设置的配置

            _services.AddSingleton<IPostConfigureOptions<OpenIdConnectOptions>, OpenIdConnectPostConfigureOptions>();
\u services.AddSingleton();
这解决了这个问题,但现在我有一个在标题中。从源代码看,似乎是因为IssuerAddress为空。我一辈子都不明白为什么。此外,我不明白为什么我需要为Microsofts自己的类添加配置才能让它工作

我知道我可以找到解决办法,但我不认为这会这么难

如果有人有任何想法,我们将非常欢迎

更新 我想扩展我发现的一些东西,由于我花在这上面的时间,这些东西最终改变了。我想特别感谢下面的各位

我最终从使用
IPostConfigure
改为使用
IConfigure
。执行此操作时,似乎要通过
iconfigureNameOptions的
Configure(name,options)
,而不是
IConfigureOptions的
Configure(options)
。因此,我实现了这两种方法。我不知道你是否必须这样做,因为我没有尝试所有可能的组合,但这样做很有效

使用
IPostConfigurationOptions
时,必须在调用
AddOpenIdConnect()
之前将其添加到服务集合中


我还删除了手动注册Microsofts
IPostConfigreOptions的行,这是不需要的。

元数据地址应该是以https://开头的绝对地址,而不是代码中的相对URL:

   options.MetadataAddress = "/" + ProtocolPath.Discovery;
然后我有点困惑为什么需要添加自己的ConfigureOpenIdConnectOptions类?要配置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;