oauth - .NET 核心 OpenId 连接服务器 : Sharing same token across multiple applications

标签 oauth asp.net-core openid-connect aspnet-contrib

我有两个用 .NET Core 编写并针对 4.6.1 的 API:

  1. myAuthApi (http://localhost:8496):验证凭据并向客户端颁发 token 。它还有一个端点/api/values/1(此操作具有 Authorize 属性,用于验证 token )
  2. myPublicApi(http://localhost:8497):它从/api/values/1 上的客户端接收 token (此操作具有授权属性,也用于验证 token )。 myPublicApi 没有任何 token 端点,旨在成为资源服务器。

我正在使用 AspNet.Security.OpenIdConnect.Server 1.0.0。 两个 API 都是 Service.Fabric 无状态服务

我可以通过以下请求格式成功获取token到http://localhost:8496/connect/token

client_id=XX&client_secret=XXX&grant_type=password&username=XXX&password=XXX

当根据 myAuthApi (http://localhost:8496/api/values/1) 验证 token 时,它有效。但是,当对 myPublicApi(http://localhost:8497/api/values/1) 使用相同的 token 时,它不会。

在这两个 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();
    }

在 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();
    }

在 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();
    }

如您所见,我的数据保护提供商将 key 存储在 Redis 中,我使用我在 2 个应用程序中共享的证书来保护 key 。 资源服务器没有配置任何身份验证提供程序,也没有在启动时使用 UseOpenIdConnectServer。在 asp.net Web API 2 中,过去使用共享机器 key 跨应用程序管理 token 解密。

如何使用 oAuthValidation 在所有其他应用程序中成功验证 myAuthApi 颁发的 token ?

编辑,一些日志可以在这里看到: https://pastebin.com/ACDz1fam

编辑2: 仔细阅读日志后,我看到 token 的解除保护使用相同的数据保护提供程序,但目的不同:

"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')."

要解决此问题,@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 使用相同的鉴别器(用于派生加密 key )并且它应该工作。

关于oauth - .NET 核心 OpenId 连接服务器 : Sharing same token across multiple applications,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45033189/

相关文章:

Facebook - OAuth token - redirect_uri 不是绝对 URL

java - Spring Boot - OAuth2 - 所有请求都被禁止

Go 中的 Azure JWT 验证不起作用

oauth-2.0 - 将 LDAP 组映射到本地 wso2 角色

java - 我可以使用 Google Plus 登录来验证我在 App Engine 中的 OAuth 方法吗?

grails - Grails中的OAuth问题

asp.net-core - 如何提供可通过 asp.net 5 中的 ConfigurationManager 访问的设置?

c# - 如何在同一个项目中针对netcoreapp2.0和net461

c# - 模拟 EF 核心 dbcontext 和 dbset

authentication - OAuth2.0中Refresh Token的使用