Token authorization in swagger in ASP.NET - c#

I am documenting the API of my application through Swagger, which works with validation through a session token, that is, through a username and password a token is generated for a certain time that allows the user to navigate the site. What I need is for swagger to capture this session token and place it in the header of the requests for the rest of the API methods automatically, the only thing I could achieve so far is to pass the token as a parameter, but doing it manually. The idea is to make it automatic. I leave the configuration of SwaggerConfig.cs that I carry for now.
public class SwaggerConfig
{
public static void Register()
{
var thisAssembly = typeof(SwaggerConfig).Assembly;
GlobalConfiguration.Configuration
// HABILITAMOS SWAGGER.
.EnableSwagger(c =>
{
var baseDirectory = AppDomain.CurrentDomain.BaseDirectory + #"\bin\";
var commentsFileName = Assembly.GetExecutingAssembly().GetName().Name + ".xml";
var commentsFile = Path.Combine(baseDirectory, commentsFileName);
c.SingleApiVersion("v1", "API");
c.OperationFilter<AddRequiredHeaderParameter>();
c.PrettyPrint();
c.ApiKey("apikey")
.Description("API Key Authentication")
.Name("Bearer")
.In("header");
c.IgnoreObsoleteActions();
c.IgnoreObsoleteProperties();
c.DescribeAllEnumsAsStrings();
.EnableSwaggerUi(c =>
{ c.DocumentTitle("DocumentaciĆ³n API");
c.EnableApiKeySupport("apikey", "header");
});
}
}
In turn, add a class to validate the application from where it is made on request
public class AddRequiredHeaderParameter : IOperationFilter
{
public void Apply(Swashbuckle.Swagger.Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
if (operation.parameters == null)
operation.parameters = new List<Parameter>();
operation.parameters.Add(new Parameter
{
name = "AuthorizedClient",
#in = "header",
type = "intenger",
description = "Aplicacion",
required = true,
#default = axaxax
});
operation.parameters.Add(new Parameter
{
name = "ClientKey",
#in = "header",
type = "string",
description = "Cliente",
required = true,
#default = "bxbxbx"
});
operation.parameters.Add(new Parameter
{
name = "Authorization",
#in = "header",
type = "apikey",
description = "Token de sesiĆ³n",
});
}
}

Related

Swagger Asp.Net Core: Security for selected functions only

I want to create a WebAPI with ASP.net Core. The API is protected by an Authorization. But not all functions are protected!
How can I realize this with Swagger?
This are my Swagger settings:
[...]
builder.Services.AddSwaggerGen(options =>
{
options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
In = ParameterLocation.Header,
Description = "Please enter a valid token",
Name = "Authorization",
Type = SecuritySchemeType.Http,
BearerFormat = "JWT",
Scheme = "Bearer"
});
options.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type=ReferenceType.SecurityScheme,
Id="Bearer"
}
},
new string[]{}
}
});
var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename));
[...]
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI(options =>
{
options.SwaggerEndpoint("/swagger/v1/swagger.json", "v1");
options.RoutePrefix = "swagger/index.html";
});
}
[...]
The functions looks like this:
/// <summary>
/// Registriert einen neuen User
/// </summary>
/// <returns></returns>
/// <response code="200">...</response>
/// <response code="400">...</response>
[HttpPost]
[Route("Register")]
[ProducesResponseType(StatusCodes.Status200OK)]
[ProducesResponseType(StatusCodes.Status400BadRequest)]
public async Task<IActionResult> Register([FromBody] UserRegistrationDto user)
{ [...] }
In Swagger it looks like this:
The lock indicates that an authorization is possible/necessary for this function. I want to remove the lock. But only for this function. How can I do this in c#?
(the swagger files are autogenerated and I don't want to modify the exported .yaml or.json file. So I need a solution which works directly in the c# code or in the swagger configuration.)
You should add Operation filter for that, as well as AllowAnonymous to the method
public class BasicAuthOperationsFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
var noAuthRequired = context.ApiDescription.CustomAttributes().Any(attr => attr.GetType() == typeof(AllowAnonymousAttribute));
if (noAuthRequired) return;
operation.Security = new List<OpenApiSecurityRequirement>
{
new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "basic"
}
},
new List<string>()
}
}
};
}
}

How to create a header that will apply to every request in the SwaggerUI for ASP NET Core application?

I'm trying to find a way to apply a header for every request to an ASP NET Core application using Swagger UI. The thing is, then I use something like IOperationFilter:
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
if (operation.Parameters == null)
operation.Parameters = new List<OpenApiParameter>();
operation.Parameters.Add(new OpenApiParameter
{
Name = "VeryImportantHeader",
In = ParameterLocation.Header,
Required = true,
Schema = new OpenApiSchema
{
Type = "String"
}
});
}
It adds a placeholder, which you should manually fill for every request, and that's kinda irritating, especially if you need to test lots of queries.
Is there a way to add a header, that will be applied to every request automatically?
For example, you can do that for the authorization, using AddSecurityDefinition:
single header placeholder example
I was looking for solution and After some search i couldn't found anything.So eventually i found a solution myself. It's probably too late for you but i put the solution here for others like me .
public class AuthorizationHeaderParameterOperationFilter:IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
operation.Security ??= new List<OpenApiSecurityRequirement>();
var tenantId = new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "Tenant-Id" } };
var userId = new OpenApiSecurityScheme { Reference = new OpenApiReference { Type = ReferenceType.SecurityScheme, Id = "User-Id" } };
operation.Security.Add(new OpenApiSecurityRequirement
{
[tenantId] = new List<string>(),
[userId] = new List<string>()
});
}
}
after creating this class. On Startup
builder.Services.AddSwaggerGen(options =>
{
options.AddSecurityDefinition("Tenant-Id", new OpenApiSecurityScheme
{
Name = "Tenant-Id",
In = ParameterLocation.Header,
Description = "Tenant Id",
Type = SecuritySchemeType.ApiKey
});
options.AddSecurityDefinition("User-Id", new OpenApiSecurityScheme
{
Name = "User-Id",
In = ParameterLocation.Header,
Description = "User Id",
Type = SecuritySchemeType.ApiKey
});
options.OperationFilter<AuthorizationHeaderParameterOperationFilter>();
});
Swagger UI Result :
request log :

ASP.NET Web Api Swagger string parameters error - no description

I am using Swagger UI to test my ASP.NET Web Api app. I added a class to allow operation parameters
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
if (operation.Parameters == null)
operation.Parameters = new List<OpenApiParameter>();
operation.Parameters.Add(new OpenApiParameter
{
Name = "ApiKey",
In = ParameterLocation.Header,
Required = true,
Schema = new OpenApiSchema
{
Type = "String"
}
});
operation.Parameters.Add(new OpenApiParameter
{
Name = "Authentication",
In = ParameterLocation.Header,
Required = false,
Schema = new OpenApiSchema
{
Type = "String"
}
});
}
In my Startup.cs, I added this line to the ConfigurationServices method
c.OperationFilter<CustomHeaderSwaggerAttribute>();
When I try and test one of the controller methods, my ApiKey string parameter always show an error no matter what I put in the textbox.
I am not sure about the Schema property but the following worked for me in past (setting the type to string):
operation.Parameters.Add(new Parameter
{
name = "ApiKey",
#in = ParameterLocation.Header,
required = true,
type = "string"
});
For more details, refer to this post

IAuthorizationFilter and IOperationFilter with swagger

Summary
What I want is to be able to add a custom AuthorizeAttribute to a method which is then recognised by swagger and displays the Available authorizations popup. The issue I'm having is getting the IOperationFilter to work correctly with the IAuthorizationFilter.
Code
startup.cs
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v2", new OpenApiInfo { Title = "API", Version = "v2" });
// Adds "(Auth)" to the summary so that you can see which endpoints have Authorization
c.OperationFilter<AppendAuthorizeToSummaryOperationFilter<Filters.Authorization2>>();
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Name = "Bearer",
Description = "Standard Authorization header using the SessionKey scheme. Example: \"{token}\"",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey
});
c.OperationFilter<Filters.AuthorizeCheckOperationFilter>();
});
controller.cs
[Filters.Authorization2]
[HttpGet]
public ApiResult<List<Request>> GetRequest(int ID)
Authorization2.cs
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method)]
public class Authorization2 : AuthorizeAttribute, IAuthorizationFilter
{
public Authorization2()
{
}
public void OnAuthorization(AuthorizationFilterContext context)
{
//Get the session from the cache
Session sess = GetSession(context.HttpContext);
if (sess.IsValid)
{
//set sess
}
else
{
//If it's not there then return with bad news
context.Result = Unauthorized();
context.HttpContext.Response.StatusCode = 401;
}
}
}
AuthorizeCheckOperationFilter.cs
internal class AuthorizeCheckOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
context.ApiDescription.TryGetMethodInfo(out var methodInfo);
if (methodInfo == null)
return;
var hasAuthorizeAttribute = false;
if (methodInfo.MemberType == MemberTypes.Method)
{
// NOTE: Check the controller itself has Authorize attribute
hasAuthorizeAttribute = methodInfo.DeclaringType.GetCustomAttributes(true).OfType<Authorization2>().Any();
// NOTE: Controller has Authorize attribute, so check the endpoint itself.
// Take into account the allow anonymous attribute
if (hasAuthorizeAttribute)
hasAuthorizeAttribute = !methodInfo.GetCustomAttributes(true).OfType<AllowAnonymousAttribute>().Any();
else
hasAuthorizeAttribute = methodInfo.GetCustomAttributes(true).OfType<Authorization2>().Any();
}
if (!hasAuthorizeAttribute)
return;
if (!operation.Responses.Any(r => r.Key == StatusCodes.Status401Unauthorized.ToString()))
operation.Responses.Add(StatusCodes.Status401Unauthorized.ToString(), new OpenApiResponse { Description = "Unauthorized" });
if (!operation.Responses.Any(r => r.Key == StatusCodes.Status403Forbidden.ToString()))
operation.Responses.Add(StatusCodes.Status403Forbidden.ToString(), new OpenApiResponse { Description = "Forbidden" });
// NOTE: This adds the "Padlock" icon to the endpoint in swagger,
// we can also pass through the names of the policies in the string[]
// which will indicate which permission you require.
operation.Security = new List<OpenApiSecurityRequirement>
{
new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
},
Scheme = "oauth2",
Name = "Bearer",
In = ParameterLocation.Header
},
new List<string>()
}
}
};
}
}
With the code as it is, the padlock on the end point shows up and the header is set but the method throws an 500 error:
System.InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found.
Attempt 1
I tried adding:
services.AddAuthentication(Microsoft.AspNetCore.Server.IISIntegration.IISDefaults.AuthenticationScheme);
but I get the same error. If I try:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(CookieAuthenticationDefaults.AuthenticationScheme,
options =>
{
options.LoginPath = new PathString("/auth/login");
options.AccessDeniedPath = new PathString("/auth/denied");
});
My request redirects to the loginPath, which causes a 404.
Attempt 2
If try a different tacktick and use a TypeFilterAttribute as so:
modify startup.cs
c.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
},
Scheme = "oauth2",
Name = "Bearer",
In = ParameterLocation.Header,
},
new List<string>()
}
});
//c.OperationFilter<Filters.AuthorizeCheckOperationFilter>();
Authorization.cs
public class AuthorizationHandler : IAuthorizationFilter
{
public AuthorizationHandler()
{
}
public void OnAuthorization(AuthorizationFilterContext context)
{
//Get the session from the cache
Session sess = GetSession(context.HttpContext);
if (sess.IsValid)
{
//set sess
}
else
{
//If it's not there then return with bad news
context.Result = Unauthorized();
context.HttpContext.Response.StatusCode = 401;
}
}
}
public class AuthorizeAttribute : TypeFilterAttribute
{
public AuthorizeAttribute() : base(typeof(AuthorizationHandler))
{
}
}
and update the method to use [Filters.Authorize] the call to the method works as expected but now every method get's the lock, not just the ones with the attribute.
Question
How do I modify my code to only have locks on the methods with the attribute and process the authorization correctly?
After following this response to a different question:
https://stackoverflow.com/a/61365691/2885471
I managed to get it to work. In essence I created a security definition in the SwaggerGen service configuration, put the security requirement in a IOperationFilter class and then add the the class to the OperationFilters.

How to pass username as base 64 encoding format in header of web api swagger?

I have implemented a web api with basic authentication filter. When I want to call it from Swagger, I am facing below problems:
1) I am unable to pass the username in Base64 encode.
2) Username is passed in Scheme property of ActionContext.Request.Headers.Authorization instead of Parameter property of the same.
I have tried with below code in swagger.
GlobalConfiguration.Configuration
.EnableSwagger(c =>
{
c.OperationFilter(() => new AddRequiredAuthorizationHeaderParameter());
});
public class AddRequiredAuthorizationHeaderParameter : IOperationFilter
{
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
var filterPipeline = apiDescription.ActionDescriptor.GetFilterPipeline();
var isAuthorized = filterPipeline.Select(filterInfo => filterInfo.Instance)
.Any(filter => filter is IAuthorizationFilter);
var allowAnonymous = apiDescription.ActionDescriptor.GetCustomAttributes<AllowAnonymousAttribute>().Any();
if (operation.parameters == null)
operation.parameters = new List<Parameter>();
operation.parameters.Add(new Parameter
{
name = "Authorization",
#in = "header",
type = "",
required = true,
description = "User Name"
});
}
}
Please help me out.

Categories

Resources