SwaggerUI с авторизацией токена-носителя .NetCore 3.0

Я пытаюсь добавить заголовок авторизации в тест SwaggerUI api. ниже мой Startup.cs

public void ConfigureServices(IServiceCollection services)
    {
       
        services.AddControllers();
        services.Configure<ApiBehaviorOptions>(options =>
        {
            options.SuppressModelStateInvalidFilter = true;
        });

        services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_3_0);

        services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo
            {
                Version = "v1",
                Title = "API",
                Description = "QPIN API with ASP.NET Core 3.0",
                Contact = new OpenApiContact()
                {
                    Name = "Tafsir Dadeh Zarrin",
                    Url = new Uri("http://www.tdz.co.ir")
                }
            });
            var securitySchema = new OpenApiSecurityScheme
            {
                Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
                Name = "Authorization",
                In = ParameterLocation.Header,
                Type = SecuritySchemeType.ApiKey
            };
            c.AddSecurityDefinition("Bearer", securitySchema);
            
            var securityRequirement = new OpenApiSecurityRequirement();
            securityRequirement.Add(securitySchema, new[] { "Bearer" });
            c.AddSecurityRequirement(securityRequirement);
            
        });
    }

    
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env, IServiceProvider serviceProvider)
    {
        app.UseCors("Cors");


        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseMiddleware<ApiResponseMiddleware>();
        app.UseSwagger();
        app.UseSwaggerUI(c =>
        {
            c.SwaggerEndpoint("/swagger/v1/swagger.json", "My API V1");
        });
        app.UseRouting();

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


        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllers();
        });

    }

Кнопка авторизации была добавлена ​​в пользовательский интерфейс Swagger, и я ввел требуемый токен доступа, как показано ниже.

но проблема в том, что когда я хочу попробовать API, токен не добавляется в запрос API, и когда я нажимаю значок замка над API, он показывает, что нет доступной авторизации, см. ниже

4 ответа

Решение

Моя реализация - исключает блокировки на незащищенных конечных точках - с OperationFilter

internal static void SwaggerSetup(this IServiceCollection services, OpenApiInfo settings)
    {
        if (settings.Version != null)
        {
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc(settings.Version, settings);
                c.OperationFilter<AddAuthHeaderOperationFilter>();
                c.AddSecurityDefinition("bearer", new OpenApiSecurityScheme
                {
                    Description = "`Token only!!!` - without `Bearer_` prefix",
                    Type = SecuritySchemeType.Http,
                    BearerFormat = "JWT",
                    In = ParameterLocation.Header,
                    Scheme = "bearer"
                });
            });
        }
    }

и OperationFilter

private class AddAuthHeaderOperationFilter : IOperationFilter
    {
        public void Apply(OpenApiOperation operation, OperationFilterContext context)
        {
            var isAuthorized = (context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any()
                                && !context.MethodInfo.DeclaringType.GetCustomAttributes(true).OfType<AllowAnonymousAttribute>().Any()) //this excludes controllers with AllowAnonymous attribute in case base controller has Authorize attribute
                                || (context.MethodInfo.GetCustomAttributes(true).OfType<AuthorizeAttribute>().Any()
                                && !context.MethodInfo.GetCustomAttributes(true).OfType<AllowAnonymousAttribute>().Any()); // this excludes methods with AllowAnonymous attribute

            if (!isAuthorized) return;

            operation.Responses.TryAdd("401", new OpenApiResponse { Description = "Unauthorized" });
            operation.Responses.TryAdd("403", new OpenApiResponse { Description = "Forbidden" });

            var jwtbearerScheme = new OpenApiSecurityScheme
            {
                Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "bearer" }
            };

            operation.Security = new List<OpenApiSecurityRequirement>
            {
                new OpenApiSecurityRequirement { [jwtbearerScheme] = new string []{} }
            };
        }
    }

Ссылка https://thecodebuzz.com/jwt-authorize-swagger-using-ioperationfilter-asp-net-core/

просто добавил условие для исключения AllowAnonymous декорированные методы

В вашем коде есть два пункта:

  1. За OpenApiSecurityRequirement в OpenApiSecurityRequirement, необходимо установить OpenApiReference
  2. Необходимо указать Scheme с участием bearer

Вот рабочая демонстрация:

services.AddSwaggerGen(c =>
{
    c.SwaggerDoc("v1", new OpenApiInfo
    {
        Version = "v1",
        Title = "API",
        Description = "QPIN API with ASP.NET Core 3.0",
        Contact = new OpenApiContact()
        {
            Name = "Tafsir Dadeh Zarrin",
            Url = new Uri("http://www.tdz.co.ir")
        }
    });
    var securitySchema = new OpenApiSecurityScheme
    {
        Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
        Name = "Authorization",
        In = ParameterLocation.Header,
        Type = SecuritySchemeType.Http,
        Scheme = "bearer",
        Reference = new OpenApiReference
        {
            Type = ReferenceType.SecurityScheme,
            Id = "Bearer"
        }
    };
    c.AddSecurityDefinition("Bearer", securitySchema);

    var securityRequirement = new OpenApiSecurityRequirement();
    securityRequirement.Add(securitySchema, new[] { "Bearer" });
    c.AddSecurityRequirement(securityRequirement);
});

Обратите внимание, что после.Net Core 3.0 тип некоторых параметров был изменен следующим образом:

In = ParameterLocation.Header,

Тип = SecuritySchemeType.ApiKey

services.AddSwaggerGen(c =>
        {
            c.SwaggerDoc("v1", new OpenApiInfo { Title = "My API", Version = "v1" });
            c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
            {
                Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
                Name = "Authorization",
                In = ParameterLocation.Header,
                Type = SecuritySchemeType.ApiKey
            });
        });

Ссылка: https://ppolyzos.com/2017/10/30/add-jwt-bearer-authorization-to-swagger-and-asp-net-core/

В дополнение к тому, что сказал Кирил, в моем случае я хочу получить токен JWT через Swagger, и это код, который я использовал, добавив OpenApiSecurityScheme к тому, что он предложил:

c.AddSecurityDefinition("bearer",
                    new OpenApiSecurityScheme{
                        Flows = new OpenApiOAuthFlows()
                        {
                            ClientCredentials = new OpenApiOAuthFlow()
                            {
                                TokenUrl = new Uri("https://auth.myauthserver.com/oauth2/token"),
                                Scopes = new Dictionary<string, string>(){ {"myscope", "Access API"}},
                                AuthorizationUrl = new Uri("https://auth.myauthserver.com/oauth2/authorize")
                            }
                        }, 
                        Type = SecuritySchemeType.OAuth2,
                        OpenIdConnectUrl = new Uri("https://myauthserver/.well-known/openid-configuration"),
                        BearerFormat = "JWT",
                        In = ParameterLocation.Header,
                        Scheme = "bearer"
                    });
Другие вопросы по тегам