[英].NET Core OpenId Connect Server: Sharing same token across multiple applications
I have two apis written in .NET Core and targeting 4.6.1: 我有两个用.NET Core编写的api,目标是4.6.1:
I am using AspNet.Security.OpenIdConnect.Server 1.0.0. 我正在使用AspNet.Security.OpenIdConnect.Server 1.0.0。 Both APIs are Service.Fabric Stateless Services 这两个API都是Service.Fabric无状态服务
I can successfully get the token with the following request format to http://localhost:8496/connect/token 我可以使用以下请求格式成功获取带有http:// localhost:8496 / connect / token的令牌
client_id=XX&client_secret=XXX&grant_type=password&username=XXX&password=XXX
When validating the token against myAuthApi ( http://localhost:8496/api/values/1 ) it works. 在针对myAuthApi( http:// localhost:8496 / api / values / 1 )验证令牌时,它可以正常工作。 However, when using that same token against myPublicApi( http://localhost:8497/api/values/1 ) it does not. 但是,当对myPublicApi( http:// localhost:8497 / api / values / 1 )使用相同的令牌时,它不会。
In both APIs, in the Startup.cs, I have 在两个API中,在Startup.cs中,我有
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// Connect to Redis database.
var redis = ConnectionMultiplexer.Connect(ConnectionHelper.GetRedisConnectionString(Configuration));
services.AddDataProtection()
.PersistKeysToRedis(redis, "DataProtection-Keys")
.ProtectKeysWithCertificate(CertificateHandler.GetX509Certificate2(Configuration));
// Add framework services.
services.AddMvc().AddJsonOptions(opts =>
{
// we set the json serializer to follow camelCaseConventions when
// receiving /replying to JSON requests
opts.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});
// we add authentication for the oAuth middleware to be registered in the DI container
services.AddAuthentication();
}
In myPublicApi I have: 在myPublicApi中我有:
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// Add a new middleware validating access tokens.
app.UseOAuthValidation(options =>
{
// Automatic authentication must be enabled
// for SignalR to receive the access token.
options.AutomaticAuthenticate = true;
options.Events = new OAuthValidationEvents
{
// Note: for SignalR connections, the default Authorization header does not work,
// because the WebSockets JS API doesn't allow setting custom parameters.
// To work around this limitation, the access token is retrieved from the query string.
OnRetrieveToken = context =>
{
// Note: when the token is missing from the query string,
// context.Token is null and the JWT bearer middleware will
// automatically try to retrieve it from the Authorization header.
context.Token = context.Request.Query["access_token"];
return Task.FromResult(0);
}
};
});
app.UseMvc();
}
In myAuthApi I have: 在myAuthApi中我有:
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
// Add a new middleware validating access tokens.
app.UseOAuthValidation(options =>
{
// Automatic authentication must be enabled
// for SignalR to receive the access token.
options.AutomaticAuthenticate = true;
options.Events = new OAuthValidationEvents
{
// Note: for SignalR connections, the default Authorization header does not work,
// because the WebSockets JS API doesn't allow setting custom parameters.
// To work around this limitation, the access token is retrieved from the query string.
OnRetrieveToken = context =>
{
// Note: when the token is missing from the query string,
// context.Token is null and the JWT bearer middleware will
// automatically try to retrieve it from the Authorization header.
context.Token = context.Request.Query["access_token"];
return Task.FromResult(0);
}
};
});
// Add a new middleware issuing access tokens.
app.UseOpenIdConnectServer(options =>
{
options.Provider = new AuthenticationProvider();
// Enable the logout, token and userinfo endpoints.
options.LogoutEndpointPath = "/connect/logout";
options.TokenEndpointPath = "/connect/token";
options.UserinfoEndpointPath = "/connect/userinfo";
CertificateHandler.SetupCommonAuthServerOptions(options, Configuration);
});
app.UseMvc();
}
As you can see, my data protection provider is storing keys in Redis, and I am protecting keys with a certificate which I am sharing across the 2 applications. 正如您所看到的,我的数据保护提供程序正在将密钥存储在Redis中,而我正在使用我在2个应用程序中共享的证书来保护密钥。 The resource server does not have any authentication provider configured and does not have UseOpenIdConnectServer in startup. 资源服务器未配置任何身份验证提供程序,并且在启动时没有UseOpenIdConnectServer。 In asp.net Web API 2, the token decryption used to be managed across the apps using shared machine keys. 在asp.net Web API 2中,令牌解密过去是使用共享机器密钥在应用程序之间进行管理的。
How can I successfully validate the token issued by myAuthApi across all other apps using oAuthValidation? 如何使用oAuthValidation成功验证myAuthApi在所有其他应用程序中发出的令牌?
EDIT, some logs can be seen here: https://pastebin.com/ACDz1fam 编辑,这里可以看到一些日志: https : //pastebin.com/ACDz1fam
EDIT2 : After reading the logs thoroughly, I saw that the unprotection of the token was using the same Data Protection Provider, but different purposes: 编辑2:彻底阅读日志后,我发现令牌的不受保护是使用相同的数据保护提供程序,但目的不同:
"Performing unprotect operation to key {4406cfa7-a588-44ba-b73a-e25817d982d9} with purposes ('C:\SfDevCluster\Data\_App\_Node_4\TestMicroServicesType_App22\PublicApiPkg.Code.1.0.1', 'OpenIdConnectServerHandler', 'AccessTokenFormat', 'ASOS')."
"Performing unprotect operation to key {4406cfa7-a588-44ba-b73a-e25817d982d9} with purposes ('C:\SfDevCluster\Data\_App\_Node_3\TestMicroServicesType_App22\AuthApiPkg.Code.1.0.1', 'OpenIdConnectServerHandler', 'AccessTokenFormat', 'ASOS')."
To fix this, @PinpointTownes suggested to setup the data protection provider like so: 要解决这个问题,@ PinpointTownes建议设置数据保护提供程序,如下所示:
var redis = ConnectionMultiplexer.Connect(ConnectionHelper.GetRedisConnectionString(Configuration));
services.AddDataProtection()
// set the application name to a common value in all apps
// to have the same purpose and share the token across apps
.SetApplicationName("MyTestMicroServices")
.PersistKeysToRedis(redis, "DataProtection-Keys")
.ProtectKeysWithCertificate(CertificateHandler.GetX509Certificate2(Configuration));
调用services.AddDataProtection().SetApplicationName("[your application name]")
以确保您的两个API使用相同的鉴别器(用于派生加密密钥),它应该工作。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.