AspNetCore.Authentication.JwtBearer выходит из строя с отсутствием SecurityTokenValidator, доступным для токена с .net core RC2

Я пытаюсь получить простую конечную работу, которая выдает и потребляет токены JWT с помощью AspNew.Security.OpenIdConnect.Server для выдачи маркера и проверки с использованием Microsoft.AspNetCore.Authentication.JwtBearer.

Я могу сгенерировать токен, но попытка аутентификации токена с ошибкой Bearer was not authenticated. Failure message: No SecurityTokenValidator available for token: {token}

В этот момент я все разобрал и имею следующее:

project.json

{
  "dependencies": {
    "Microsoft.AspNetCore.Mvc": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Server.IISIntegration": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Server.Kestrel": "1.0.0-rc2-final",
    "Microsoft.Extensions.Configuration.EnvironmentVariables": "1.0.0-rc2-final",
    "Microsoft.Extensions.Configuration.FileExtensions": "1.0.0-rc2-final",
    "Microsoft.Extensions.Configuration.Json": "1.0.0-rc2-final",
    "Microsoft.Extensions.Logging": "1.0.0-rc2-final",
    "Microsoft.Extensions.Logging.Console": "1.0.0-rc2-final",
    "Microsoft.Extensions.Logging.Debug": "1.0.0-rc2-final",
    "AspNet.Security.OAuth.Validation": "1.0.0-alpha1-final",
    "AspNet.Security.OpenIdConnect.Server": "1.0.0-beta5-final",
    "Microsoft.AspNetCore.Authentication": "1.0.0-rc2-final",
    "Microsoft.AspNetCore.Authentication.JwtBearer": "1.0.0-rc2-final"
  },

  "tools": {
    "Microsoft.AspNetCore.Server.IISIntegration.Tools": {
      "version": "1.0.0-preview1-final",
      "imports": "portable-net45+win8+dnxcore50"
    }
  },

  "frameworks": {
    "net461": { }
  },

  "buildOptions": {
    "emitEntryPoint": true,
    "preserveCompilationContext": true
  },

  "publishOptions": {
    "include": [
      "wwwroot",
      "Views",
      "appsettings.json",
      "web.config"
    ]
  },

  "scripts": {
    "postpublish": [ "dotnet publish-iis --publish-folder %publish:OutputPath% --framework %publish:FullTargetFramework%" ]
  }
}

Методы Startup.cs:

// This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
            services.AddAuthorization(options =>
                {
                    options.AddPolicy(JwtBearerDefaults.AuthenticationScheme,
                        builder =>
                        {
                            builder.
                            AddAuthenticationSchemes(JwtBearerDefaults.AuthenticationScheme).
                            RequireAuthenticatedUser().
                            Build();
                        }
                    );
                }
            );

            services.AddAuthentication();
            services.AddDistributedMemoryCache();
            services.AddMvc();
            services.AddOptions();
        }

        // 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)
        {
            loggerFactory.AddConsole(Configuration.GetSection("Logging"));
            loggerFactory.AddDebug();

            var jwtOptions = new JwtBearerOptions()
            {
                AuthenticationScheme = JwtBearerDefaults.AuthenticationScheme,
                AutomaticAuthenticate = true,
                Authority = "http://localhost:5000/",
                Audience = "http://localhost:5000/",
                RequireHttpsMetadata = false
            };

            jwtOptions.ConfigurationManager = new ConfigurationManager<OpenIdConnectConfiguration>
                (
                    metadataAddress: jwtOptions.Authority + ".well-known/openid-configuration",
                    configRetriever: new OpenIdConnectConfigurationRetriever(),
                    docRetriever: new HttpDocumentRetriever { RequireHttps = false }
                );


            app.UseJwtBearerAuthentication(jwtOptions);

            app.UseOpenIdConnectServer(options =>
            {
                options.AllowInsecureHttp = true;
                options.AuthorizationEndpointPath = Microsoft.AspNetCore.Http.PathString.Empty;
                options.Provider = new OpenIdConnectServerProvider
                {
                    OnValidateTokenRequest = context =>
                    {
                        context.Skip();
                        return Task.FromResult(0);
                    },

                    OnGrantResourceOwnerCredentials = context =>
                    {
                        var identity = new ClaimsIdentity(context.Options.AuthenticationScheme);
                        identity.AddClaim(ClaimTypes.NameIdentifier, "[unique id]");

                        identity.AddClaim("urn:customclaim", "value", OpenIdConnectConstants.Destinations.AccessToken, OpenIdConnectConstants.Destinations.IdentityToken);

                        var ticket = new AuthenticationTicket(
                            new ClaimsPrincipal(identity),
                            new Microsoft.AspNetCore.Http.Authentication.AuthenticationProperties(),
                            context.Options.AuthenticationScheme);

                        ticket.SetScopes("profile", "offline_access");

                        context.Validate(ticket);

                        return Task.FromResult(0);
                    }
                };
            });            

            app.UseMvc();
        }

отправка x-url-кодированного POST в http://localhost:5000 с помощью grant_type = password, username = foo, password = bar генерирует ожидаемый access_token.

Я добавил атрибут [Authorize("Bearer")] в ValuesController, и он работает так, как ожидалось, в JwtBearerMiddlewear вызывается, но я не могу проверить маркер.

Кто-нибудь получил эту работу с .net core RC2? У меня есть то же самое, что работает на RC1, но не смог этого добиться.

Спасибо.

Ответ 1

Начиная с beta5 (для ASP.NET Core RC2), промежуточное ПО сервера OpenID не использует JWT как формат по умолчанию для токенов доступа. Вместо этого он использует непрозрачные маркеры, зашифрованные встроенным стеком ASP.NET Core Data Protection (точно так же, как файлы cookie для проверки подлинности).

У вас есть 3 варианта исправления ошибки, которую вы видите:

  • Используйте новое промежуточное программное обеспечение проверки OAuth2, разработанное для поддержки непрозрачных токенов ( рекомендуемая опция, если ваш API и ваш сервер авторизации входит в одно и то же приложение). Для этого сохраните ссылку AspNet.Security.OAuth.Validation у вас в project.json и замените app.UseJwtBearerAuthentication(...) просто app.UseOAuthValidation(). Вы также можете удалить Microsoft.AspNetCore.Authentication.JwtBearer из project.json.

  • Заставьте промежуточное ПО сервера OpenID Connect использовать токены JWT, вызвав options.AccessTokenHandler = new JwtSecurityTokenHandler(); в параметрах. Обратите внимание, что вам также нужно вызвать ticket.SetResources(...), чтобы добавить соответствующую аудиторию к токенам JWT (см. Этот SO post для получения дополнительной информации).

  • Используйте новое промежуточное ПО для интроспекции. Этот параметр более сложный и требует выполнения события ValidateIntrospectionRequest для проверки учетных данных клиента. Используйте его только в том случае, если вы знаете, что делаете.