Токен носителя JWT ASP.Net Core 3.0 Нет SecurityTokenValidator

Я использую API ASP.Net Core 3.0 с EntityFramework Core в качестве UserStorage. Startup.cs:

        public void ConfigureServices(IServiceCollection services)
            {
             using Microsoft.AspNetCore.Authentication.JwtBearer;
             using Microsoft.AspNetCore.Builder;
             using Microsoft.AspNetCore.Hosting;
             using Microsoft.AspNetCore.Identity;
             using Microsoft.AspNetCore.SpaServices.AngularCli;
             using Microsoft.EntityFrameworkCore;
             using Microsoft.Extensions.Configuration;
             using Microsoft.Extensions.DependencyInjection;
             using Microsoft.Extensions.Hosting;
             using Microsoft.IdentityModel.Tokens;
             using System;
             using System.Collections.Generic;
             using System.Linq;
             using System.Text;
             using System.Threading.Tasks;
                .
                .
                .

                //Add Identity Provider with EntityFramework
                services.AddIdentity<User, IdentityRole>()
                .AddEntityFrameworkStores<ApplicationDBContext>()
                .AddDefaultTokenProviders();

                //Initialize EntityFramework
                services.AddDbContext<ApplicationDBContext>(options => options.UseSqlite(Configuration.GetConnectionString("localDB")));

                //Initialize JWT Authentication
                services.AddAuthentication(options => {
                    options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
                    options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
                }).AddJwtBearer(jwtBearerOptions =>
                {
                    jwtBearerOptions.TokenValidationParameters = new TokenValidationParameters()
                    {
                        ValidateIssuer = true,
                        ValidateAudience = true,
                        ValidateLifetime = true,
                        ValidateIssuerSigningKey = true,

                        ValidIssuer = "http://localhost:44352",
                        ValidAudience = "http://localhost:44352",
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration.GetSection("Secrets")["jwt"]))
                    };
                }
                );
                services.AddMvc(options => options.EnableEndpointRouting = false)
                    .AddNewtonsoftJson();

                // In production, the Angular files will be served from this directory
                services.AddSpaStaticFiles(configuration =>
                {
                    configuration.RootPath = "ClientApp/dist";
                });
            }

            .
            .
            .


                app.UseHttpsRedirection();
                app.UseStaticFiles();
                app.UseSpaStaticFiles();

                //Enable Authentication
                app.UseAuthentication();
                app.UseAuthorization();

                .
                .
                .

                app.UseMvc(routes =>
                {
                    routes.MapRoute(
                        name: "default",
                        template: "{controller}/{action=Index}/{id?}");
                });


    .
    .
    .

Это мой код, выдающий токен JWT:


public async Task<IActionResult> Login()
        {
            using (var reader = new StreamReader(Request.Body))
            {
                var body = await reader.ReadToEndAsync();
                var cred = JsonConvert.DeserializeObject<Credentials>(body);
                var result = (await userService.LoginUser(cred.userName, cred.password));
                if (result == 200)
                {

                    var secretKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(configuration.GetSection("Secrets")["jwt"]));
                    var signinCredentials = new SigningCredentials(secretKey, SecurityAlgorithms.HmacSha256Signature);

                    var roles = await userService.GetRoleFromUsername(cred.userName);
                    var rolesString = JsonConvert.SerializeObject(roles);

                    var tokeOptions = new JwtSecurityToken(
                                issuer: "http://localhost:44352",
                                audience: "http://localhost:44352",
                                claims: new List<Claim>(new List<Claim> {
                                        new Claim("userName",cred.userName),
                                        new Claim("roles", rolesString)
                                }),
                                expires: DateTime.Now.AddHours(1),
                                signingCredentials: signinCredentials
                    );

Это мой вызов API с использованием авторизации:


[Route("api/videos/add")]
[Authorize(Roles = "Admin")]
[HttpPost]
public async Task<IActionResult> AddVideo()
{
    using (var reader = new StreamReader(Request.Body))
    {
        var body = await reader.ReadToEndAsync();
        var video = JsonConvert.DeserializeObject<Video>(body);
        await videoService.AddVideo(video);
        return Ok();
    }
}

Мои пакеты NuGet:

  • Microsoft.EntityFrameworkCore {3.0.0-preview5.19227.1}
  • Microsoft.EntityFrameworkCore.Sqlite {3.0.0-preview5.19227.1}
  • Microsoft.AspNetCore.Authentication.JwtBearer {3.0.0-preview4-19216-03}
  • Microsoft.EntityFrameworkCore.Sqlite.Core {3.0.0-preview5.19227.1}
  • Microsoft.NETCore.Platforms {3.0.0-preview4.19212.13}
  • Microsoft.AspNetCore.Mvc.NewtonsoftJson {3.0.0-preview5-19227-01}
  • Microsoft.AspNetCore.SpaServices.Extensions {3.0.0-preview5-19227-01}
  • Microsoft.AspNetCore.Identity.EntityFrameworkCore {3.0.0-preview5-19227-01}
  • runtime.win-x64.Microsoft.NETCore.DotNetAppHost {3.0.0-preview4-27615-11}

У меня проблема в том, что если я вызываю эту часть API, я получаю сообщение об ошибке:

Информация: предъявитель не был аутентифицирован. Сообщение об ошибке: для токена недоступен SecurityTokenValidator:

Любая помощь будет принята с благодарностью, так как я не могу найти ошибку


person Dieter Köberl    schedule 03.06.2019    source источник
comment
Вы можете попробовать эту ссылку   -  person Tony Ngo    schedule 03.06.2019
comment
Спасибо за ваш ответ. К сожалению, я не использую OpenID Connect   -  person Dieter Köberl    schedule 03.06.2019
comment
Нет ли ванильного способа добиться этого?   -  person Dieter Köberl    schedule 08.06.2019
comment
Используйте ClaimTypes.Role вместо "roles" в списке претензий. Какое содержание rolesString?   -  person rst    schedule 11.06.2019
comment
Спасибо за ваш ответ. Содержимое roleString - это List ‹string›, который преобразуется в строку с помощью JsonConvert.SerializeObject ().   -  person Dieter Köberl    schedule 11.06.2019


Ответы (3)


Попробуйте использовать ClaimTypes.Role вместо roles, если вы хотите добавить роль в качестве утверждения.

var tokeOptions = new JwtSecurityToken(
                            issuer: "http://localhost:44352",
                            audience: "http://localhost:44352",
                            claims: new List<Claim>(new List<Claim> {
                                    new Claim("userName",cred.userName),
                                    new Claim(ClaimTypes.Role, "Admin")                                      
                            }),
                            expires: DateTime.Now.AddHours(1),
                            signingCredentials: signinCredentials
                );
person Ryan    schedule 10.06.2019
comment
Спасибо за ваш ответ. К сожалению, этого не произошло. У меня все та же ошибка - person Dieter Köberl; 10.06.2019
comment
Он хорошо работает в моем проекте asp.net core 2.2, когда я тестирую его с помощью почтальона. Как вы тестируете api? - person Ryan; 11.06.2019
comment
Я тестирую Angular7 SPA, над разработкой - person Dieter Köberl; 11.06.2019

Благодаря Xing Zou я разобрался в корне ошибки. Проблема заключалась в том, что я отправил токен на предъявителя в кавычках.

Запрос

Ошибка в API теперь исчезла, проблема в том, что авторизация теперь не выполняется в API, и он возвращает 403.

РЕДАКТИРОВАТЬ:

Я обнаружил проблему, связанную с ошибкой 403. Кажется, вам разрешено отправлять только ОДНУ роль в токене-носителе для ASP.Net для ее проверки. Тип возвращаемого значения userManager.GetRolesAsync предполагает, что у пользователя может быть несколько ролей, которые могут быть включены в токен-носитель JWT.

Это означает, что моя проблема исправлена.

Хочу всех поблагодарить за ответы. Без тебя я бы его не получил!

person Dieter Köberl    schedule 11.06.2019

Я справился с этой проблемой так:

client.DefaultRequestHeaders.Add("Authorization", $"Bearer {token.Replace("\"", "")}");

Не лучшее решение, но сработало.

person DanielV    schedule 03.12.2019