I have bearer token configured in my projects:
- Security API
Nuget packages installed:
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.8" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="6.25.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.25.1" />
Program.cs:
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System.Text;
using System.Text.Json.Serialization;
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddControllers(options =>
{
options.OutputFormatters.RemoveType<HttpNoContentOutputFormatter>();
}).AddJsonOptions(x =>
{
// serialize enums as strings in api responses (e.g. Role)
x.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
// ignore omitted parameters on models to enable optional params (e.g. User update)
x.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
});
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
// builder.Services.AddSwaggerGen();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "JWTToken_Auth_API", Version = "v1" });
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
{
Name = "Authorization",
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer",
BearerFormat = "JWT",
In = ParameterLocation.Header,
Description = "JWT Authorization header using the Bearer scheme. \r\n\r\n Enter 'Bearer' [space] and then your token in the text input below.\r\n\r\nExample: \"Bearer 1safsfsdfdfd\"",
});
c.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
}
},
new string[] {}
}
});
});
//Add Jwt Token functionality
// Add authentication
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
//options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.SaveToken = true;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new TokenValidationParameters()
{
ClockSkew = TimeSpan.Zero,
ValidateIssuerSigningKey = bool.Parse(builder.Configuration["JsonWebTokenKeys:ValidateIssuerSigningKey"]),
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JsonWebTokenKeys:IssuerSigningKey"])),
ValidateIssuer = bool.Parse(builder.Configuration["JsonWebTokenKeys:ValidateIssuer"]),
//ValidAudience = builder.Configuration["JsonWebTokenKeys:ValidAudience"],
//ValidIssuer = builder.Configuration["JsonWebTokenKeys:ValidIssuer"],
ValidateAudience = bool.Parse(builder.Configuration["JsonWebTokenKeys:ValidateAudience"]),
RequireExpirationTime = bool.Parse(builder.Configuration["JsonWebTokenKeys:RequireExpirationTime"]),
//ValidateLifetime = bool.Parse(builder.Configuration["JsonWebTokenKeys:ValidateLifetime"])
};
});
// CORS
builder.Services.AddCors(p => p.AddPolicy("cors", builder =>
{
builder.WithOrigins("*").AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
}));
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCors();
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
AppSettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"JsonWebTokenKeys": {
"ValidateIssuerSigningKey": true,
"IssuerSigningKey": "W3YN3-101101-2022",
"ValidateIssuer": false,
"ValidIssuer": "https://localhost:7273",
"ValidateAudience": false,
"ValidAudience": "https://localhost:7273",
"RequireExpirationTime": true,
"ValidateLifetime": true
}
}
Product API
Nuget packages installed:
<PackageReference Include="Microsoft.AspNetCore.Authentication.JwtBearer" Version="6.0.8" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning" Version="5.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Mvc.Versioning.ApiExplorer" Version="5.0.0" />
<PackageReference Include="Microsoft.IdentityModel.JsonWebTokens" Version="6.25.1" />
<PackageReference Include="Swashbuckle.AspNetCore" Version="6.2.3" />
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="6.25.1" />
ConfigureSwaggerOptions.cs:
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.Extensions.Options;
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
namespace ProductAPI.Extensions
{
public class ConfigureSwaggerOptions : IConfigureNamedOptions<SwaggerGenOptions>
{
private readonly IApiVersionDescriptionProvider provider;
public ConfigureSwaggerOptions(IApiVersionDescriptionProvider provider)
{
this.provider = provider;
}
public void Configure(SwaggerGenOptions options)
{
// add swagger document for every API version discovered
foreach (var description in provider.ApiVersionDescriptions)
{
options.SwaggerDoc(
description.GroupName,
CreateVersionInfo(description));
options.AddSecurityDefinition(
description.GroupName,
CreateSecurityScheme());
options.AddSecurityRequirement(CreateSecurityRequirement());
}
}
public void Configure(string name, SwaggerGenOptions options)
{
Configure(options);
}
private OpenApiInfo CreateVersionInfo(ApiVersionDescription description)
{
var info = new OpenApiInfo()
{
Title = "API Products",
Version = description.ApiVersion.ToString()
};
if (description.IsDeprecated)
{
info.Description = " This API version has been deprecated.";
}
return info;
}
private OpenApiSecurityScheme CreateSecurityScheme()
{
var securityScheme = new OpenApiSecurityScheme()
{
Name = "Authorization",
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer",
BearerFormat = "JWT",
In = ParameterLocation.Header,
Description = "JWT Authorization header using the Bearer scheme. \r\n\r\n Enter 'Bearer' [space] and then your token in the text input below.\r\n\r\nExample: \"Bearer token\"",
};
return securityScheme;
}
private OpenApiSecurityRequirement CreateSecurityRequirement()
{
var securityRequirement = new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"}
}, new string[] {}
}
};
return securityRequirement;
}
}
}
Program.cs:
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.Mvc.ApiExplorer;
using Microsoft.AspNetCore.Mvc.Formatters;
using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System.Text.Json.Serialization;
using System.Text;
using ProductAPI.Extensions;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers(options =>
{
options.OutputFormatters.RemoveType<HttpNoContentOutputFormatter>();
options.SuppressImplicitRequiredAttributeForNonNullableReferenceTypes = true; //deshabilitar validacion automatica
}).AddJsonOptions(x =>
{
// serialize enums as strings in api responses (e.g. Role)
x.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter());
// ignore omitted parameters on models to enable optional params (e.g. User update)
x.JsonSerializerOptions.DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull;
});
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.ConfigureOptions<ConfigureSwaggerOptions>();
// Add Jwt Token functionality
// Add Authentication
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
//options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
}).AddJwtBearer(options =>
{
options.SaveToken = true;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new TokenValidationParameters()
{
ClockSkew = TimeSpan.Zero,
ValidateIssuerSigningKey = bool.Parse(builder.Configuration["JsonWebTokenKeys:ValidateIssuerSigningKey"]),
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["JsonWebTokenKeys:IssuerSigningKey"])),
ValidateIssuer = bool.Parse(builder.Configuration["JsonWebTokenKeys:ValidateIssuer"]),
//ValidAudience = builder.Configuration["JsonWebTokenKeys:ValidAudience"],
//ValidIssuer = builder.Configuration["JsonWebTokenKeys:ValidIssuer"],
ValidateAudience = bool.Parse(builder.Configuration["JsonWebTokenKeys:ValidateAudience"]),
RequireExpirationTime = bool.Parse(builder.Configuration["JsonWebTokenKeys:RequireExpirationTime"]),
ValidateLifetime = bool.Parse(builder.Configuration["JsonWebTokenKeys:ValidateLifetime"])
};
});
//CORS
builder.Services.AddCors(p => p.AddPolicy("cors", builder =>
{
builder.WithOrigins("*").AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod();
}));
// API Versioning
builder.Services.AddApiVersioning(options =>
{
options.AssumeDefaultVersionWhenUnspecified = true;
options.DefaultApiVersion = new ApiVersion(4, 0);
options.ReportApiVersions = true;
});
builder.Services.AddVersionedApiExplorer(setup =>
{
setup.GroupNameFormat = "'v'VVV";
setup.SubstituteApiVersionInUrl = true;
});
var app = builder.Build();
var provider = app.Services.GetRequiredService<IApiVersionDescriptionProvider>();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(options =>
{
foreach (var description in provider.ApiVersionDescriptions)
{
options.SwaggerEndpoint($"/swagger/{description.GroupName}/swagger.json",
description.GroupName.ToUpperInvariant());
}
});
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCors();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
app.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
app.Run();
AppSettings.json:
{
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft.AspNetCore": "Warning"
}
},
"AllowedHosts": "*",
"JsonWebTokenKeys": {
"ValidateIssuerSigningKey": true,
"IssuerSigningKey": "W3YN3-101101-2022",
"ValidateIssuer": false,
"ValidIssuer": "https://localhost:7273",
"ValidateAudience": false,
"ValidAudience": "https://localhost:7273",
"RequireExpirationTime": true,
"ValidateLifetime": true
}
}
ProductController:
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Cors;
using Microsoft.AspNetCore.Mvc;
namespace ProductAPI.Controllers
{
[ApiController]
[EnableCors("cors")]
[Authorize]
[Route("v{version:apiVersion}/[Controller]")]
[ApiVersion("1.0")]
public class ProductController : Controller
{
private static readonly string[] Summaries = new[]
{
"Product #1", "Product #2", "Product #3"
};
[MapToApiVersion("1.0")]
[HttpGet]
public IActionResult Index()
{
return Ok(Summaries);
}
}
}
When I use postman the endpoints respond to the tokens I send but when I try to invoke them from the swagger UI the token value is not sent:
This is the address of my repository:
https://github.com/Weyne/aspnetcore_swagger
CodePudding user response:
In CreateSecurityRequirement
, when instantiating OpenApiSecurityScheme
, you need to provide Id of the version group you were using in options.SwaggerDoc
and options.AddSecurityDefinition
:
public void Configure(SwaggerGenOptions options)
{
// add swagger document for every API version discovered
foreach (var description in provider.ApiVersionDescriptions)
{
options.SwaggerDoc(
description.GroupName,
CreateVersionInfo(description));
options.AddSecurityDefinition(
description.GroupName,
CreataeSecurityScheme());
// pass the group name here:
options.AddSecurityRequirement(
CreateSecurityRequirement(description.GroupName));
}
}
private OpenApiSecurityRequirement CreateSecurityRequirement(string groupName)
{
var securityRequirement = new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
// not "Bearer" here, as it was copied form VanillaProject
{ Type = ReferenceType.SecurityScheme, Id = groupName }
},
new string[] { }
}
};
return securityRequirement;
}