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 для получения дополнительной информации).
- Используйте новое промежуточное программное обеспечение для самоанализа. Этот вариант является более сложным и требует реализации
ValidateIntrospectionRequest
событие для проверки учетных данных клиента. Используйте его, только если знаете, что делаете.
Боковое примечание, если у кого-то такая же ошибка ( для токена нет SecurityTokenValidator):
Дважды проверьте, что заголовок аутентификации, отправленный клиентом, действительно имеет правильный формат:
Authorize: Bearer [ey....]
Нет SecurityTokenValidator для маркера ошибки указывает на то, что не зарегистрировано ни одного для формата заголовка авторизации , найденного в запросе обработчика. Например, у вас будет эта ошибка, если полученный запрос содержит значение заголовка «Bearer Bearer ey82383...», или если ключевое слово «Bearer» пропущено или написано с ошибкой.