Сервер идентификации 4 не может подтвердить мой токен доступа

#c# #asp.net-core #asp.net-web-api #identityserver4

#c# #asp.net-core #asp.net-web-api #identityserver4

Вопрос:

Я использую Asp.net Ядро 3.1 Веб-Api для создания Api и использования сервера идентификации 4 (3.1.2) с asp.net ядро идентификации в одном проекте (оба в одном проекте) Для аутентификации пользователя. Сервер идентификации 4 генерирует токен доступа, но при вызове Api с Postman каждый раз возвращает 401. Это конфигурация моего сервера идентификации 4:

  "IdentityServerSetting": {
    "IdentityServerAuthority": "https://localhost:5000",
    "IdentityResources": [
      "openID"
    ],
    "ApiResources": [
      {
        "Name": "MadPay",
        "DisplayName": "MadPay Api",
        "UserClaims": [
          "name",
          "Email"
        ]
      }
    ],
    "Client": [
      {
        "AccessTokenLifeTime": 3600,
        "AllowedGrantTypes": "password",
        "ClientId": "angular",
        "AlwaysIncludeUserClaimsInIdToken": "true",
        "AlwaysSendClientClaims": "true",
        "AllowCorsOrigins": [ "https://localhost:5000" ],
        "RequireClientSecret": "false",
        "AllowedScopes": [ "OpenId", "MadPay" ],
        "AllowOfflineAccess": "true"
      }
    ]
  }
  

Это мой конфигурационный сервис

 public void ConfigureServices(IServiceCollection services)
        {
            services.Configure<JwtConfig>(_configuration.GetSection(nameof(JwtConfig)));
            services.Configure<IdentityServerSetting>(_configuration.GetSection(nameof(IdentityServerSetting)));

            services.AddScoped<IUnitOfWork, UnitOfWork<ApplicationDBContext>>();

            services.AddMapperConfigurations();
            services.AddServices();

            services.AddDbContext<ApplicationDBContext>(opt =>
            {
                opt.UseSqlServer(_configuration.GetConnectionString("ApplicationConnection"));
            });

            services.AddMvcCore(opt => opt.EnableEndpointRouting = false)
             .SetCompatibilityVersion(CompatibilityVersion.Version_3_0)
             .AddAuthorization()
             .AddNewtonsoftJson(options =>
                    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);

            services.AddResponseCaching();
            services.AddIdentityServerConfig(_identityServerSetting);
            services.AddApiAuthorization();

            services.AddCors();
            services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
            services.Configure<ApiBehaviorOptions>(options =>
            {
                options.SuppressModelStateInvalidFilter = true;
            });
        }
  

Это моя настройка

  public void Configure(IApplicationBuilder app, IHostEnvironment env)
        {
            IdentityModelEventSource.ShowPII = true;
            if (env.IsDevelopment())
            {
                app.UseDeveloperExceptionPage();
            }
            else
            {
                // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
                app.UseHsts();
            }

            //app.UseHsts();

            app.UseCors(i => i.AllowAnyOrigin().AllowAnyMethod().AllowAnyHeader());
            app.AddExceptionHandling();
            app.UseResponseCaching();
            app.UseIdentityServer();
            app.UseHttpContext();
            app.UseHttpsRedirection();
            app.UseStaticFiles();

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

AddApiAuthorization Fuction

  public static void AddApiAuthorization(this IServiceCollection services)
        {
            services.AddAuthentication(options =>
            {
                options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
                options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            })
                .AddJwtBearer(opt =>
                 {
                     opt.Authority = "https://localhost:5000";
                     opt.RequireHttpsMetadata = false;
                     //opt.Audience = "MadPay";
                     opt.TokenValidationParameters = new TokenValidationParameters
                     {
                         ValidateAudience = false
                     };
                 });

 services.AddScoped<IAuthorizationHandler, PermissionAuthorizationHandler>();

            services.AddAuthorization(option =>
                option.AddPolicy("Permission", builder =>
                    builder.AddRequirements(new PermissionRequirement()).RequireAuthenticatedUser()
                )
            );
}
  

Функция AddIdentityServerConfig

  public static void AddIdentityServerConfig(this IServiceCollection services, IdentityServerSetting config)
        {
            var finalConfig = MapJsonToConfig(config);

            services.AddIdentity<User, Role>(opt =>
            {
                opt.Password.RequireLowercase = false;
                opt.Password.RequireUppercase = false;
                opt.Password.RequireNonAlphanumeric = false;

                opt.User.RequireUniqueEmail = true;

                opt.SignIn.RequireConfirmedAccount = true;
                opt.SignIn.RequireConfirmedEmail = true;
            })
            .AddEntityFrameworkStores<ApplicationDBContext>()
            .AddUserManager<AppUserManager>()
            //.AddSignInManager<AppSignInManager>()
            .AddErrorDescriber<AppErrorDescriberService>()
            .AddDefaultTokenProviders();

            services.AddIdentityServer(options =>
            {
                options.Events.RaiseErrorEvents = true;
                options.Events.RaiseInformationEvents = true;
                options.Events.RaiseFailureEvents = true;
                options.Events.RaiseSuccessEvents = true;
            })

                    .AddDeveloperSigningCredential()
                    .AddInMemoryIdentityResources(finalConfig.IdentityResources)
                    .AddInMemoryApiResources(finalConfig.Apis)
                    .AddInMemoryClients(finalConfig.Clients)
                    .AddAspNetIdentity<User>()
                    .AddResourceOwnerValidator<AppIdentityPasswordValidator<User>>();
        }
  

Это моя загрузка из токена доступа

 
{
  "nbf": 1597823415,
  "exp": 1597827015,
  "iss": "https://localhost:5000",
  "aud": "MadPay",
  "client_id": "angular",
  "sub": "1",
  "auth_time": 1597823413,
  "idp": "local",
  "name": "osali",
  "scope": [
    "MadPay",
    "offline_access"
  ],
  "amr": [
    "pwd"
  ]
}
  

И для Call Api используйте этот URL: https://localhost:5000 /…
И отправить токен в заголовке авторизации: Bearer ….

я думаю, что выпущенный токен доступа не является проблемой. Я потратил несколько дней и не могу понять, почему не работает, и очень смущен, что не так!!

Комментарии:

1. можете ли вы опубликовать копию токена и как выглядит ваш запрос postman? Используете ли вы какие-либо политики авторизации в API? или как защищены контроллеры API?

2. Я отредактировал свой вопрос и добавил больше деталей.

3. Я обновил свой ответ ниже, это помогает?

Ответ №1:

Вы могли бы установить для всех параметров проверки токена значение false, а затем включить их один за другим, чтобы увидеть, что вызывает ошибку.

             options.TokenValidationParameters.ValidateAudience = false;
            options.TokenValidationParameters.ValidateIssuer = false;
            options.TokenValidationParameters.ValidateIssuerSigningKey = false;
            options.TokenValidationParameters.ValidateLifetime = false;
            options.TokenValidationParameters.ValidateTokenReplay = false;
  

Вы также можете попробовать включить следующее и проверить ответ от API в postman или Fiddler.

             //True if token validation errors should be returned to the caller.
            options.IncludeErrorDetails = true;
  

Как защищены контроллеры API? Используете ли вы какие-либо политики авторизации?

При запуске вашего API вы не должны использовать IdentityServer, вместо этого вы должны использовать метод AddMyJwtBearer. и в вашем методе настройки вы должны использовать:

         app.UseAuthentication();
        app.UseAuthorization();
  

Вот пример класса startup.cs для типичного API:

 public class Startup
{
    // This method gets called by the runtime. Use this method to add services to the container.
    // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices(IServiceCollection services)
    {
        services.AddControllersWithViews();

        
        services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
        .AddMyJwtBearer(options =>
        {

            options.Audience = "payment";
            options.Authority = "https://localhost:6001/";

            //True if token validation errors should be returned to the caller.
            options.IncludeErrorDetails = true;

            //If the signing key is not found, do a refresh from the JWKS endpoint
            //This allows for automatic recovery in the event of a  key rollover
            options.RefreshOnIssuerKeyNotFound = true;

            //Gets or sets if HTTPS is required for the metadata address or authority.
            //Should always be true in production!
            options.RequireHttpsMetadata = true;

            //True if the token should be stored in the AuthenticationProperties
            //after a successful authorization.
            options.SaveToken = true;

            //Parameters
            options.TokenValidationParameters.ClockSkew = TimeSpan.FromMinutes(5);
            options.TokenValidationParameters.NameClaimType = "name";
            options.TokenValidationParameters.RoleClaimType = "role";

        });
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        app.UseHttpsRedirection();

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();


        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });
    }
}
  

В дополнение к этому ответу я написал сообщение в блоге, в котором более подробно рассматривается эта тема:
Устранение проблем с аутентификацией JwtBearer в ASP.NET Ядро

Комментарии:

1. Это не работает, я добавляю проект в Gitlab, ссылка , чтобы увидеть весь код. Спасибо

2. В проекте Api используйте IdentityServer4 И Asp.net Общая идентификация ядра, если не использовать IdentityServer, то localhost: 5000 / connect / token не может получить доступ и не может сгенерировать токен

3. эта ошибка не помогает?trce: IdentityServer4.Hosting. EndpointRouter[0] Запись конечной точки не найдена для пути запроса: /api /WeatherForecast

4. в моем примере попробуйте удалить часть /api / из URL. это помогает? или измените мой шаблон на шаблон: «api / {controller} / {action} / {id?}»); Я вижу, что ваш код в GitLab использует старый ASP.NET Основной стиль кодирования. Более современно использовать app.UseRouting(); и app. Используйте конечные точки ().

5. Не исправлено! Мой URL-адрес Api и URL-адрес сервера идентификации одинаковы: localhost: 5000 и оба используют https, это неправильно??

Ответ №2:

вы пропускаете ниже :-

 app.UseAuthentication();
app.UseAuthorization();
  

можете ли вы добавить выше в метод настройки startup.cs в api и попробовать?

Комментарии:

1. @AliBelyani- к какой конечной точке api вы обращаетесь? если это конечная точка weatherForecast get, вы можете захотеть проверить атрибут разрешения, если это дает вам желаемый результат.