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

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

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

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

Благодарю.

2 ответа

Решение

Начиная с бета5 (для ASP.NET Core RC2), промежуточное ПО сервера OpenID Connect больше не использует 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 для получения дополнительной информации).

Боковое примечание, если у кого-то такая же ошибка ( для токена нет SecurityTokenValidator):

Дважды проверьте, что заголовок аутентификации, отправленный клиентом, действительно имеет правильный формат:

      Authorize: Bearer [ey....]

Нет SecurityTokenValidator для маркера ошибки указывает на то, что не зарегистрировано ни одного для формата заголовка авторизации , найденного в запросе обработчика. Например, у вас будет эта ошибка, если полученный запрос содержит значение заголовка «Bearer Bearer ey82383...», или если ключевое слово «Bearer» пропущено или написано с ошибкой.

Другие вопросы по тегам