linux 服务器上的 OpenIddict 颁发者验证失败
OpenIddict Issuer validation failed on linux server
基于 OpenIddict 的身份服务器在其自己的 [授权] 控制器中验证令牌,但在通过 /introspect 端点从另一个资源服务器访问时拒绝令牌。
在开发机器上一切正常。这是在将服务部署到 Linux 服务器后发生的,其中服务托管在同一台机器的不同端口上。
这是我日志中的实际异常:
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidIssuerException: IDX10205: Issuer validation failed. Issuer: 'System.String'. Did not match: validationParameters.ValidIssuer: 'System.String' or validationParameters.ValidIssuers: 'System.String'.
设置与此类似:
https://github.com/openiddict/openiddict-samples/blob/dev/samples/Zirku/Zirku.Server/Startup.cs
这是我的 openiddict 设置:
services.AddOpenIddict()
.AddCore(options =>
{
// Configure OpenIddict to use the Entity Framework Core stores and models.
// Note: call ReplaceDefaultEntities() to replace the default OpenIddict entities.
options.UseEntityFrameworkCore()
.UseDbContext<ApplicationDbContext>();
}).AddServer(options =>
{
// Enable the authorization, logout, token and userinfo endpoints.
options.SetAuthorizationEndpointUris("/connect/authorize")
.SetLogoutEndpointUris("/connect/logout")
.SetTokenEndpointUris("/connect/token")
.SetIntrospectionEndpointUris("/connect/introspect")
.SetUserinfoEndpointUris("/connect/userinfo");
// Mark the "email", "profile" and "roles" scopes as supported scopes.
options.RegisterScopes(OpenIddictConstants.Scopes.Email, OpenIddictConstants.Scopes.Profile,
OpenIddictConstants.Scopes.Roles);
// Note: this sample only uses the authorization code flow but you can enable
// the other flows if you need to support implicit, password or client credentials.
options.AllowAuthorizationCodeFlow().RequireProofKeyForCodeExchange();
options.AllowClientCredentialsFlow();
options.AllowPasswordFlow();
options.AllowRefreshTokenFlow();
// Register the signing and encryption credentials.
options.AddDevelopmentEncryptionCertificate();
// .AddDevelopmentSigningCertificate();
// Encryption and signing of tokens
options.AddEphemeralEncryptionKey()
.AddEphemeralSigningKey();
options.RegisterScopes(ApplicationConstants.MobileApiResource);
options.SetAccessTokenLifetime(TimeSpan.FromMinutes(5));
options.SetIdentityTokenLifetime(TimeSpan.FromMinutes(15));
options.SetRefreshTokenLifetime(TimeSpan.FromHours(1));
// Register the ASP.NET Core host and configure the ASP.NET Core-specific options.
options.UseAspNetCore()
//todo remove the disable transport layer security
.DisableTransportSecurityRequirement()
.EnableAuthorizationEndpointPassthrough()
.EnableLogoutEndpointPassthrough()
.EnableTokenEndpointPassthrough()
.EnableUserinfoEndpointPassthrough()
.EnableStatusCodePagesIntegration();
options.DisableAccessTokenEncryption();
})
.AddValidation(options =>
{
// Import the configuration from the local OpenIddict server instance.
options.UseLocalServer();
// Register the ASP.NET Core host.
options.UseAspNetCore();
});
这是我的设置 API:
services.AddAuthentication(options =>
{
options.DefaultScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme;
});
services.AddOpenIddict()
.AddValidation(options =>
{
// Note: the validation handler uses OpenID Connect discovery
// to retrieve the address of the introspection endpoint.
options.SetIssuer(identityUrl);
options.AddAudiences("client_id");
// Configure the validation handler to use introspection and register the client
// credentials used when communicating with the remote introspection endpoint.
options.UseIntrospection()
.SetClientId("client_id")
.SetClientSecret("secret");
// Register the System.Net.Http integration.
options.UseSystemNetHttp();
// Register the ASP.NET Core host.
options.UseAspNetCore();
});
最后在师兄的帮助下,我们才得以诊断出问题所在。此问题与 nginx 有关。
The server was only returning the issuer domain address but not the port, itwas returning xyz.com as the issuer instead of the actual issuer address xyz.com:5001
正确的解决方法是调整 nginx conf 代理的 Host header 指令。
改变了这个:
proxy_set_header Host $host;
为此:
proxy_set_header Host $http_host;
还将此添加到身份服务器的 Startup.cs:
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
基于 OpenIddict 的身份服务器在其自己的 [授权] 控制器中验证令牌,但在通过 /introspect 端点从另一个资源服务器访问时拒绝令牌。
在开发机器上一切正常。这是在将服务部署到 Linux 服务器后发生的,其中服务托管在同一台机器的不同端口上。
这是我日志中的实际异常:
Microsoft.IdentityModel.Tokens.SecurityTokenInvalidIssuerException: IDX10205: Issuer validation failed. Issuer: 'System.String'. Did not match: validationParameters.ValidIssuer: 'System.String' or validationParameters.ValidIssuers: 'System.String'.
设置与此类似: https://github.com/openiddict/openiddict-samples/blob/dev/samples/Zirku/Zirku.Server/Startup.cs
这是我的 openiddict 设置:
services.AddOpenIddict()
.AddCore(options =>
{
// Configure OpenIddict to use the Entity Framework Core stores and models.
// Note: call ReplaceDefaultEntities() to replace the default OpenIddict entities.
options.UseEntityFrameworkCore()
.UseDbContext<ApplicationDbContext>();
}).AddServer(options =>
{
// Enable the authorization, logout, token and userinfo endpoints.
options.SetAuthorizationEndpointUris("/connect/authorize")
.SetLogoutEndpointUris("/connect/logout")
.SetTokenEndpointUris("/connect/token")
.SetIntrospectionEndpointUris("/connect/introspect")
.SetUserinfoEndpointUris("/connect/userinfo");
// Mark the "email", "profile" and "roles" scopes as supported scopes.
options.RegisterScopes(OpenIddictConstants.Scopes.Email, OpenIddictConstants.Scopes.Profile,
OpenIddictConstants.Scopes.Roles);
// Note: this sample only uses the authorization code flow but you can enable
// the other flows if you need to support implicit, password or client credentials.
options.AllowAuthorizationCodeFlow().RequireProofKeyForCodeExchange();
options.AllowClientCredentialsFlow();
options.AllowPasswordFlow();
options.AllowRefreshTokenFlow();
// Register the signing and encryption credentials.
options.AddDevelopmentEncryptionCertificate();
// .AddDevelopmentSigningCertificate();
// Encryption and signing of tokens
options.AddEphemeralEncryptionKey()
.AddEphemeralSigningKey();
options.RegisterScopes(ApplicationConstants.MobileApiResource);
options.SetAccessTokenLifetime(TimeSpan.FromMinutes(5));
options.SetIdentityTokenLifetime(TimeSpan.FromMinutes(15));
options.SetRefreshTokenLifetime(TimeSpan.FromHours(1));
// Register the ASP.NET Core host and configure the ASP.NET Core-specific options.
options.UseAspNetCore()
//todo remove the disable transport layer security
.DisableTransportSecurityRequirement()
.EnableAuthorizationEndpointPassthrough()
.EnableLogoutEndpointPassthrough()
.EnableTokenEndpointPassthrough()
.EnableUserinfoEndpointPassthrough()
.EnableStatusCodePagesIntegration();
options.DisableAccessTokenEncryption();
})
.AddValidation(options =>
{
// Import the configuration from the local OpenIddict server instance.
options.UseLocalServer();
// Register the ASP.NET Core host.
options.UseAspNetCore();
});
这是我的设置 API:
services.AddAuthentication(options =>
{
options.DefaultScheme = OpenIddictValidationAspNetCoreDefaults.AuthenticationScheme;
});
services.AddOpenIddict()
.AddValidation(options =>
{
// Note: the validation handler uses OpenID Connect discovery
// to retrieve the address of the introspection endpoint.
options.SetIssuer(identityUrl);
options.AddAudiences("client_id");
// Configure the validation handler to use introspection and register the client
// credentials used when communicating with the remote introspection endpoint.
options.UseIntrospection()
.SetClientId("client_id")
.SetClientSecret("secret");
// Register the System.Net.Http integration.
options.UseSystemNetHttp();
// Register the ASP.NET Core host.
options.UseAspNetCore();
});
最后在师兄的帮助下,我们才得以诊断出问题所在。此问题与 nginx 有关。
The server was only returning the issuer domain address but not the port, itwas returning xyz.com as the issuer instead of the actual issuer address xyz.com:5001
正确的解决方法是调整 nginx conf 代理的 Host header 指令。
改变了这个:
proxy_set_header Host $host;
为此:
proxy_set_header Host $http_host;
还将此添加到身份服务器的 Startup.cs:
app.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});