I installed swagger in visual studio 2015 web application and it's working good.But Authorization part is missing in that part how can i add authorization header in c# mvc web application Swagger.
Thanks in Advance.
http://prntscr.com/h1ohww.
1, Write a filter
public class MyHeaderFilter : IOperationFilter
{
public void Apply(Operation operation, SchemaRegistry schemaRegistry, ApiDescription apiDescription)
{
if (operation.parameters == null)
operation.parameters = new List<Swashbuckle.Swagger.Parameter>();
operation.parameters.Add(new Swashbuckle.Swagger.Parameter
{
name = "Authorization",
type = "string",
#in = "header",
required = false // set to false if this is optional
});
}
}
2, Enable this filter in Swagger config in Startup.cs
config.EnableSwagger(c =>
{
c.SingleApiVersion("v1", "SwaggerUi");
c.IncludeXmlComments(string.Format(#"{0}\bin\{1}.XML", AppDomain.CurrentDomain.BaseDirectory, typeof(SwaggerConfig).Assembly.GetName().Name));
c.IncludeXmlComments(string.Format(#"{0}\bin\{1}.XML", AppDomain.CurrentDomain.BaseDirectory, "Elephant.Entity"));
c.OperationFilter<MyHeaderFilter>();
})
.EnableSwaggerUi(c =>
{
});
Good luck!
Related
I have configured AzureAd token authentication for my webAPI but in swagger page its showing the actual clientId value but I don't want to show the actual value of ClientId to the end user. That means in the code I can hardcode but in the swagger page I want to show some dummy value, how that can be done?
In the clientId textbox, I want to pass any random value like 'swaggerClient'
services.AddSwaggerGen(op =>
{
var openApi = new OpenApiSecurityScheme
{
Flows = new OpenApiOAuthFlows
{
AuthorizationCode = new OpenApiOAuthFlow
{
AuthorizationUrl = "https://abcde.com",
Scopes = new Dictionary<string, string>
{
{ Scope, "mvc1"}
},
TokenUrl = "https://abcde.com/token"
}
},
In = ParameterLocation.Header,
Name = "Authorization",
Type = SecuritySchemeType.OAuth2
};
op.AddSecurityRequirement(new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "oauth2"
}
},
new string[] {}
}
});
options.AddSecurityDefinition("oauth2", openApi);
options.OperationFilter<SecurityRequirementsOperationFilter>();
});
Client_id is not hided as that it is not a secret as OAuth specification RFC 6749 - The OAuth 2.0 Authorization Framework indicates and it is exposed to the resource owner and must be used along with client secret for client authentication and secret is hided anyway.
Please check if the parameter can be hidden by using SchemaFilter with IgnoreDataMember something like C# ASP.NET : Hide model properties from Swagger doc - DEV Community
GET the client id from getter and setter class
[IgnoreDataMember]
public string ClientId { set; get; }
use ISchemaFilter to control it. Add new class.
using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;
using System.Linq;
using System.Reflection;
using System.Runtime.Serialization;
namespace swaggertest
{
public class MySwaggerSchemaFilter : ISchemaFilter
{
public void Apply(OpenApiSchema schema, SchemaFilterContext context)
{
if (schema?.Properties == null)
{
return;
}
var ignoreDataMemberProperties = context.Type.GetProperties()
.Where(t => t.GetCustomAttribute<IgnoreDataMemberAttribute>() != null);
foreach (var ignoreDataMemberProperty in ignoreDataMemberProperties)
{
var propertyToHide = schema.Properties.Keys
.SingleOrDefault(x => x.ToLower() == ignoreDataMemberProperty.Name.ToLower());
if (propertyToHide != null)
{
schema.Properties.Remove(propertyToHide);
}
}
}
}
}
And then specifying in the start up
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "swaggertest", Version = "v1" });
c.SchemaFilter<MySwaggerSchemaFilter>();
});
...
}
Or by changing the DOM properties as suggested by kievu in github issue
You can raise a azure support request or swagger support regarding the same.
References:
Testing Azure AD-protected APIs, part 1: Swagger UI - Joonas W's
blog
How To Swagger Hide API Or Route Method – Guidelines |TheCodeBuzz
I have 3 projects:
Net Core 3.1 MVC project.
Net Core 3.1 Web Api project with JWT auth --> connected to db via Entity Framework
(Xamarin app that also uses the web api for authentication and data retrieval).
I do not want to connect separately to the same db from both projects (1,2) (does not feel like a good idea, correct me if im wrong, would like to keep the db crud operations contained to the web api).
I want to do the authentication in the Web Api project and pass the token to the Net Core MVC project.
I do not know how to use the token to authorize this user for the MVC
project, so that controllers can be accessed based on the user's role
etc. Basically log this user in in the MVC project with the token
obtained in the web api. Is this even possible or a proper method? Any
help please?
MVC project
Startup.cs class
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
// add for razor pages and refresh without rebuilding
services.AddRazorPages().AddRazorRuntimeCompilation();
// add httpClient
services.AddHttpClient();
// start auth jwt
services.AddSession(options => {
options.IdleTimeout = TimeSpan.FromMinutes(1);
});
//services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
//Provide a secret key to Encrypt and Decrypt the Token
var SecretKey = Encoding.ASCII.GetBytes
("mySecretKeyForAuthenticationAndAuthorization");
//Configure JWT Token Authentication
services.AddAuthentication(auth =>
{
auth.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
auth.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(token =>
{
token.RequireHttpsMetadata = false;
token.SaveToken = true;
token.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
//Same Secret key will be used while creating the token
IssuerSigningKey = new SymmetricSecurityKey(SecretKey),
ValidateIssuer = true,
//Usually, this is your application base URL
ValidIssuer = "https://myAzureWebAPi.azurewebsites.net",
ValidateAudience = true,
//Here, we are creating and using JWT within the same application.
//In this case, base URL is fine.
//If the JWT is created using a web service, then this would be the consumer URL.
ValidAudience = "https://mylocalhost/",
RequireExpirationTime = true,
ValidateLifetime = true,
ClockSkew = TimeSpan.Zero
};
});
// end auth jwt
// add for roles authorization
services.AddAuthorization(config =>
{
config.AddPolicy(Policies.Admin, Policies.AdminPolicy());
config.AddPolicy(Policies.Client, Policies.ClientPolicy());
});
services.AddControllersWithViews();
}
// 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();
}
else
{
app.UseExceptionHandler("/Home/Error");
// 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.UseHttpsRedirection();
app.UseStaticFiles();
//add for jwt
app.UseCookiePolicy();
app.UseSession();
//Add JWToken to all incoming HTTP Request Header
app.Use(async (context, next) =>
{
var JWToken = context.Session.GetString("JWToken");
if (!string.IsNullOrEmpty(JWToken))
{
context.Request.Headers.Add("Authorization", "Bearer " + JWToken);
}
await next();
});
app.UseRouting();
// added for jwt
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{area=Client}/{controller=LoginPage}/{action=Index}/{id?}");
});
}
}
MVC LoginPageController.cs
[Area("Client")]
public class LoginPageController : Controller
{
private readonly IHttpClientFactory _clientFactory;
public LoginPageController(IHttpClientFactory clientFactory)
{
_clientFactory = clientFactory;
}
public IActionResult Index()
{
return View();
}
[HttpPost]
public async Task<IActionResult> Login([Bind] LoginModel loginModel)
{
var client = _clientFactory.CreateClient();
//var client = new HttpClient();
try
{
var json = JsonConvert.SerializeObject(loginModel);
var content = new StringContent(json, Encoding.UTF8, "application/json");
var outcome = await client.PostAsync("https://<AzureWebAPiUrl>/api/accounts/login", content);
if (outcome!= null && outcome.IsSuccessStatusCode)
{
var jsonResult = await outcome.Content.ReadAsStringAsync();
var token = JsonConvert.DeserializeObject<Token>(jsonResult);
Console.WriteLine(token.user_role);
// store token in a session
HttpContext.Session.SetString("JWToken", token.access_token);
// Here is the problem, once I have the token how do I make this user be
//authenticated in the mvc project so that the [Authorize[Role = "someRole"] on controllers works
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return RedirectToAction("Index", "AdminDeals", new { area = "Admin"}); // only if role is admin
}
}
Hey I have solution for this please refer below point
first of all you need to add authentication. public void ConfigureServices(IServiceCollection services)
services.AddSession();
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = >JwtBearerDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = >JwtBearerDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;
})
// Adding Jwt Bearer
.AddJwtBearer(options =>
{
options.SaveToken = true;
options.RequireHttpsMetadata = false;
options.TokenValidationParameters = new TokenValidationParameters()
{
ValidateIssuer = true,
ValidateAudience = true,
ValidAudience = Configuration["JWTConfig:ValidAudience"],
ValidIssuer = Configuration["JWTConfig:ValidIssuer"],
IssuerSigningKey = new >SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["JWTConfig:Secret"]))
};
});
After that you have to Use Session for storing authentication token and in this token you have to encrypt token combination of role list whatever role want to pass for the authorization.
Here i have used JWT Bearer token
Using this session you have to configure in public void Configure(IApplicationBuilder app, IWebHostEnvironment env)startup.cs file for use header authentication.
app.UseSession();
app.Use(async (context, next) =>
{
var token = context.Session.GetString("Token");
if (!string.IsNullOrEmpty(token))
{
context.Request.Headers.Add("Authorization", "Bearer " + token);
}
await next();
});
then after you you have to add in your controller
[Authorize(Roles = "Employee,Student")]
public ActionResult Leave()
{
// your code here
}
This is a typical scenario that you should implement OAuth2.0 for your application- You have 2 kinds of clients (MVC and Xamrin), both of them need to be authenticated then access your API project, your API should be protected by a identity provider instead of doing the authenticate by itself. In asp.net core, the most popular solution is Identity Server 4, you don't have to reinvent the wheel , just create an Identity Provider sever, and config your API and MVC project based on the instruction in their documents and everything is ok then. Meanwhile, Identity Server 4 support entity framework
I am using Swagger in a .NET COre API project.
Is there a way to apply JWT Authentication in Swagger UI only for some endpoints?
I put [Authorize] Attribute only on a few calls (also have tried putting [AllowAnonymous] on the calls that don't need authentication), but when I open the Swagger UI page, the lock symbol is on all the endpoints.
You'll have to create an IOperationFilter to only add the OpenApiSecurityScheme to certain endpoints. How this can be done is described in this blog post (adjusted for .NET Core 3.1, from a comment in the same blog post).
In my case, all endpoints defaults to [Authorize] if not [AllowAnonymous] is explicitly added (also described in the linked blog post). I then create the following implementation of IOperationFilter:
public class SecurityRequirementsOperationFilter : IOperationFilter
{
public void Apply(OpenApiOperation operation, OperationFilterContext context)
{
if (!context.MethodInfo.GetCustomAttributes(true).Any(x => x is AllowAnonymousAttribute) &&
!(context.MethodInfo.DeclaringType?.GetCustomAttributes(true).Any(x => x is AllowAnonymousAttribute) ?? false))
{
operation.Security = new List<OpenApiSecurityRequirement>
{
new OpenApiSecurityRequirement
{
{
new OpenApiSecurityScheme {
Reference = new OpenApiReference {
Type = ReferenceType.SecurityScheme,
Id = "bearer"
}
}, new string[] { }
}
}
};
}
}
}
You'll have to tweak the if statement if you don't default all endpoints to [Authorize].
Finally, where I call services.AddSwaggerGen(options => { ... } (usually in Startup.cs) I have the following line:
options.OperationFilter<SecurityRequirementsOperationFilter>();
Note that the above line will replace the (presumably) existing call to options.AddSecurityRequirement(...) in the same place.
Is there example code of a breeze/angular client app using ASP.Net Core Breeze server?
It looks like there are the following Nuget packages:- Breeze.AspNetCore.NetCore and Breeze.Composite.AspNetCore.EF6
It would be really helpful to have the TempHire example using this technology.
Can you point me in the right direction? re. frontend/backend code example
Any help appreciated.
This is a bit of a journey because right now there are a lot of moving parts. I have had some success in getting this to work but there are some limitations for example i cannot use .expand('entityName') on the client.
I am using .NET CORE 3.0 preview with Entity Framework Core. I have attached an image of all the dependencies i have installed. Not all of them are required but probably used in a API project.
The most important parts of the below code snippet are to setup the NewtonsoftJson settings.
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers().AddNewtonsoftJson(options =>
{
options.SerializerSettings.DateTimeZoneHandling = DateTimeZoneHandling.Utc;
//THE BELOW LINE IS IMPORTANT OTHERWISE IT WILL CAMELCASE TO THE SERVER
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
//THE BELOW LINE PREVENTS LOOPING ENTITY REFs
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
var connection = #"Server=tcp:XXXXX.database.windows.net,1433;Initial Catalog=DBNAME;Persist Security Info=False;User ID=XXX;Password=XXXXX;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;";
//THIS IS WHERE YOU ARE GOING TO MAKE YOUR CONTEXT INJECTABLE
services.AddDbContext<YOURCONTEXTContext>(options => options.UseSqlServer(connection, x => x.UseNetTopologySuite()));
var appSettingsSection = Configuration.GetSection("AppSettings");
services.Configure<AppSettings>(appSettingsSection);
// configure jwt authentication
var appSettings = appSettingsSection.Get<AppSettings>();
var key = Encoding.ASCII.GetBytes(appSettings.Token);
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options => {
options.RequireHttpsMetadata = false;
options.SaveToken = true;
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
};
});
}
// 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();
}
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.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader());
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
}
Then you need to setup your breeze controller:
using Microsoft.AspNetCore.Authorization;
using System.Linq;
using HB.Data.Models;
using Microsoft.AspNetCore.Http;
using System.Security.Claims;
using System;
using Microsoft.AspNetCore.Mvc;
using Breeze.AspNetCore;
using HB.API.Manager;
using HB.BusinessFacade.Business;
using GeoAPI.Geometries;
using NetTopologySuite.Geometries;
using Breeze.Persistence;
using System.Threading.Tasks;
using System.Collections.Generic;
using Newtonsoft.Json.Linq;
namespace HB.API.Controllers
{
[BreezeQueryFilter]
[Route("api/[controller]/[action]")]
public class BreezeController : ControllerBase
{
private YOURCONTEXTContext _context;
private hbPersistenceManager PersistenceManager;
string UserID;
public BreezeController(YOURCONTEXTContext context, IHttpContextAccessor httpContextAccessor)
{
this._context = context;
PersistenceManager = new hbPersistenceManager(context);
//this.UserID = httpContextAccessor.HttpContext.User.FindFirst(ClaimTypes.NameIdentifier).Value;
}
[HttpGet]
public string Metadata()
{
return PersistenceManager.Metadata();
}
}
And then just a little helper that i use for the PersistenceManager
using HB.Data.Models;
using Breeze.Persistence.EFCore;
namespace HB.API.Manager
{
public class hbPersistenceManager : EFPersistenceManager<YOURCONTEXTContext>
{
public hbPersistenceManager(YOURCONTEXTContext dbContext) : base(dbContext) { }
}
}
Please see this example: https://github.com/Breeze/northwind-demo
It is a full working example with a .NET Core 2.2 backend and Angular 8 front end, and includes TypeScript class generation so that the client-side TypeScript model matches the server-side C# model and database.
The example repo includes steps to create the entire app from scratch.
I have an IdentityServer4 server with a custom identity resource:
new IdentityResource
{
Name = "custom.profile",
UserClaims = new[] { "location" }
}
This resource is used by the users of an ASP.NET MVC client connecting wiht OIDC hybrid flow and no consent page:
new Client
{
ClientId = "client.mvc",
ClientName = "MVC Core Client",
AllowedGrantTypes = GrantTypes.Hybrid,
...
AllowedScopes =
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
"custom.profile"
},
Login is done manually in <idsrv>/Login/DoLogin:
public async Task<IActionResult> DoLogin(LoginInputModel model)
{
if (ModelState.IsValid)
{
if (model.Username == "test.user" && model.Password == "password")
{
Guid userId = new Guid("8da49efb-a1aa-4253-bb7f-56cc6c532b78");
await HttpContext.Authentication.SignInAsync(userId.ToString(), model.Username);
if (_interaction.IsValidReturnUrl(model.ReturnUrl))
{
return Redirect(model.ReturnUrl);
}
return Redirect("~/");
}
ModelState.AddModelError("", "Invalid username or password.");
}
My question is, how/where do I populate this "location" value of the "custom.profile" scope for the user?
You basically need to implement the GetProfileDataAsync method on the IProfileService service to add some claims.
So in startup make sure you have something like:
identityServerBuilder.Services.AddScoped<IProfileService, ProfileService>();
And then in your ProfileService class have something like this:
public Task GetProfileDataAsync(ProfileDataRequestContext context) {
context.IssuedClaims.Add(new Claim()); //Your claims(s)
}