I currently have 3 different cultures.
Actually, my url looks like www.website.com/services, no mater what culture is selected (the culture value is stored in a cookie).
What I would like to do is display the culture directly in the url like this: www.website.com/en/services.
How can I achieve that in .NET6 and with only Razor pages?
Program class
var builder = WebApplication.CreateBuilder(args);
builder.Services.AddRazorPages();
builder.Services.AddMvc().AddViewLocalization(LanguageViewLocationExpanderFormat.Suffix).AddDataAnnotationsLocalization();
builder.Services.Configure<RequestLocalizationOptions>(opt =>
{
var supportedCultures = new List<CultureInfo>
{
new CultureInfo("en"),
new CultureInfo("fr"),
new CultureInfo("nl")
};
opt.DefaultRequestCulture = new RequestCulture("en");
opt.SupportedCultures = supportedCultures;
opt.SupportedUICultures = supportedCultures;
});
builder.Services.AddHttpContextAccessor();
builder.Services.AddLocalization(opt => { opt.ResourcesPath = "Resources"; });
var app = builder.Build();
// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/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();
app.UseRouting();
app.UseAuthorization();
app.UseRequestLocalization(((IApplicationBuilder)app).ApplicationServices.GetRequiredService<IOptions<RequestLocalizationOptions>>().Value);
app.MapRazorPages();
app.Run();
You need to create a custom IPageRouteModelConvention:
public class CultureTemplatePageRouteModelConvention : IPageRouteModelConvention
{
public void Apply(PageRouteModel model)
{
var selectorCount = model.Selectors.Count;
for (var i = 0; i < selectorCount; i++)
{
var selector = model.Selectors[i];
model.Selectors.Add(new SelectorModel
{
AttributeRouteModel = new AttributeRouteModel
{
Order = -1,
Template = AttributeRouteModel.CombineTemplates("{culture?}", selector.AttributeRouteModel.Template),
}
});
}
}
}
Then register it using:
builder.Services.AddRazorPages()
.AddRazorPagesOptions(options =>
{
options.Conventions.Add(new CultureTemplatePageRouteModelConvention());
});
Finally configure RequestLocalizationOptions:
builder.Services.Configure<RequestLocalizationOptions>(opt =>
{
var supportedCultures = new List<CultureInfo>
{
new CultureInfo("en"),
new CultureInfo("fr"),
new CultureInfo("nl")
};
opt.DefaultRequestCulture = new RequestCulture("en");
opt.SupportedCultures = supportedCultures;
opt.SupportedUICultures = supportedCultures;
// add this line
opt.RequestCultureProviders.Insert(0, new RouteDataRequestCultureProvider());
});
To add the culture to your links you can use the asp-route-culture attribute:
<a asp-route-culture="#Request.RouteValues["culture"]" asp-page="/Contact">Contact</a>
More info about the anchor tag helper and the asp-route-{value} attribute: https://learn.microsoft.com/en-us/aspnet/core/mvc/views/tag-helpers/built-in/anchor-tag-helper?view=aspnetcore-6.0#asp-route-value
Source: https://www.mikesdotnetting.com/article/348/razor-pages-localisation-seo-friendly-urls
Related
How to configure IIS from a webapi that was in net3.1 in net7.0
?
I have an application in net7 that should run on the server on top of iis, but I don't know how to configure it in net7, before there was a solution made in 3.1
What I have today:
var assembly = Assembly.GetExecutingAssembly()
?? throw new InvalidOperationException("It was not possible to get executing assembly information");
var options = new WebApplicationOptions()
{
ContentRootPath = AppContext.BaseDirectory,
Args = args,
ApplicationName = assembly.GetName().Name
};
var builder = WebApplication.CreateBuilder(options);
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
builder.Host.UseWindowsService();
}
builder.Configuration.AddJsonFile("hostsettings.json", true);
builder.Configuration
.SetBasePath(builder.Environment.ContentRootPath)
.AddJsonFile("appsettings.json", false, true)
.AddJsonFile($"appsettings.{builder.Environment.EnvironmentName}.json", true, true)
.AddEnvironmentVariables();
builder.Services.AddCors(options =>
{
options.AddDefaultPolicy(
policy =>
{
policy.AllowAnyOrigin();
policy.AllowAnyHeader();
policy.AllowAnyMethod();
});
});
builder.Services.AddControllers().AddJsonOptions(options =>
{
options.JsonSerializerOptions.PropertyNamingPolicy = null;
});
builder.Services.AddControllers();
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddLogger();
var app = builder.Build();
if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}
app.UseCors();
app.MapControllers();
app.Run();
The Client application makes double queries to a single resource on the server. The first frame has no authorization header and the second frame does. Unfortunately, after reading the first frame, the server does not get the second frame. How to handle it on the ASP.NET CORE 5 server?
Endpoint for testing.
value always = {} when i call from client, from postman everything is working
[ApiExplorerSettings(IgnoreApi = true)]
[HttpPost("Service")]
public IActionResult GetHeader()
{
var value = HttpContext.Request.Headers["Authorization"];
return Ok();
}
app.UseMiddleware<SerilogMiddleware>();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<NotificationHub>("/api/socket");
endpoints.UseSoapEndpoint<SVPService.SVPServiceSoap>((options) =>
{
options.Path = "/Service.asmx";
options.Binding = new BasicHttpBinding()
{
TextEncoding = new UTF8Encoding(false),
Security = new BasicHttpSecurity()
{
Mode = BasicHttpSecurityMode.TransportCredentialOnly,
Transport = new HttpTransportSecurity() { ClientCredentialType = HttpClientCredentialType.Basic }
}
};
options.SoapSerializer = SoapSerializer.XmlSerializer;
}).RequireAuthorization();
});
app.UseMvc();
Logged Request from client on node.js server to get headers.
First Request Headers
{
'user-agent': 'Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 4.0.30319.42000)',
'content-type': 'text/xml; charset=utf-8',
'content-length': '806',
expect: '100-continue',
connection: 'Keep-Alive'
}
Second Request Headers
{
'user-agent': 'Mozilla/4.0 (compatible; MSIE 6.0; MS Web Services Client Protocol 4.0.30319.42000)',
'content-type': 'text/xml; charset=utf-8',
authorization: 'Basic dGVzdG93ZV91c2VybmFtZTp0ZXN0b3dlX3Bhc3N3b3Jk',
'content-length': '806',
expect: '100-continue'
}
Its a my startup.cs file
public void ConfigureServices(IServiceCollection services)
{
services.AddCors(options => options.AddPolicy("CorsPolicy", builder =>
{
builder
//.AllowAnyOrigin()
.AllowAnyHeader()
.AllowAnyMethod()
.AllowCredentials().SetIsOriginAllowed(hostName => true);
}));
services.AddQuartz();
services.Configure<JwtAuthentication>(Configuration.GetSection("JwtAuthentication"));
services.AddAuthentication("BasicAuthentication")
.AddScheme<AuthenticationSchemeOptions, BasicAuthenticationHandler>("BasicAuthentication", null);
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo
{
Version = "xxx",
Title = "xxx",
Description = "xxx",
Contact = new OpenApiContact
{
Name = "xxx",
Email = "xxx",
Url = new Uri("xxx"),
},
});
// Set the comments path for the Swagger JSON and UI.
string xmlFile = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
string xmlPath = Path.Combine(AppContext.BaseDirectory, xmlFile);
c.IncludeXmlComments(xmlPath);
});
MapperConfiguration mappingConfig = new MapperConfiguration(mc =>
{
mc.AddProfile(new MappingProfile());
});
IMapper mapper = mappingConfig.CreateMapper();
services.AddSingleton(mapper);
services.AddSignalR().AddNewtonsoftJsonProtocol();
services.AddSingleton<ITokenService, TokenService>();
services.AddSingleton<IPasswordService, PasswordService>();
services.AddSingleton<IUserProfile, UserProfile>();
services.AddSingleton<IReceiptService, ReceiptService>();
services.AddSingleton<ISend, Send>();
services.AddSingleton<IEncryption, Encryption>();
services.AddSingleton<ParkingTicketManagementServiceV3, TicketManagement>();
services.AddScoped<SVPService.SVPServiceSoap, SVPServiceSoap>();
services.AddScoped<IManageSVP, ManageSVP>();
services.AddScoped<IStripeMethods, StripeMethods>();
services.AddScoped<IManageSchedullerRecurringPayment, ManageSchedullerRecurringPayment>();
services.AddRepository();
services.AddSingleton<IAuthorizationHandler, DenyAnonymousAuthorizationRequirement>();
services.AddMvc(options =>
{
options.InputFormatters.Insert(0, new RawJsonBodyInputFormatter());
options.EnableEndpointRouting = false;
})
.SetCompatibilityVersion(CompatibilityVersion.Latest)
.AddNewtonsoftJson(opt =>
{
opt.SerializerSettings.ContractResolver = new DefaultContractResolver() { NamingStrategy = new LowerCaseNamingStrategy() };
opt.SerializerSettings.StringEscapeHandling = Newtonsoft.Json.StringEscapeHandling.Default;
opt.SerializerSettings.Converters.Add(new Newtonsoft.Json.Converters.StringEnumConverter());
opt.SerializerSettings.DateTimeZoneHandling = Newtonsoft.Json.DateTimeZoneHandling.Utc;
opt.SerializerSettings.MaxDepth = null;
opt.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
services.AddSwaggerGenNewtonsoftSupport();
services.AddControllers();
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseFileServer(new FileServerOptions
{
FileProvider = new PhysicalFileProvider(
Path.Combine(Directory.GetCurrentDirectory(), "StaticFile")),
RequestPath = "/staticfile"
});
app.UseCors("CorsPolicy");
app.UseHttpsRedirection();
app.UseSwagger();
app.UseReDoc(c =>
{
c.SpecUrl = "xxx";
c.DocumentTitle = "xxx";
});
app.UseMiddleware<SerilogMiddleware>();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<NotificationHub>("/api/socket");
endpoints.UseSoapEndpoint<SVPService.SVPServiceSoap>((options) =>
{
options.Path = "/Service.asmx";
options.Binding = new BasicHttpBinding()
{
TextEncoding = new UTF8Encoding(false),
Security = new BasicHttpSecurity()
{
Mode = BasicHttpSecurityMode.TransportCredentialOnly,
Transport = new HttpTransportSecurity() { ClientCredentialType = HttpClientCredentialType.Basic }
}
};
options.SoapSerializer = SoapSerializer.XmlSerializer;
}).RequireAuthorization();
});
app.UseMvc();
}
}
Just check if the response has the correct headers
Yes,
To answer my question the header was actually missing the WWW-Authenticate: Basic realm = header.
I have a strange problem my translations are always coming back in English. I have made sure that edge has the languages installed but still its always English. BTW as a test I only have the words of different countries in the text to ensure they get rendered.
public void ConfigureServices(IServiceCollection services) {
services.AddLocalization(options => options.ResourcesPath = "Resources");
services.AddSingleton<LocalizationService>();
services.AddDbContext<MISDBContext>
(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<ApplicationUser>()
AddEntityFrameworkStores<MISDBContext()
.AddClaimsPrincipalFactory<MyUserClaimsPrincipalFactory>(); //<---- add this line
services.AddControllersWithViews()
.AddDataAnnotationsLocalization();
services.Configure<RequestLocalizationOptions>(options => {
var supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("en-GB"),
new CultureInfo("es"),
new CultureInfo("fr")
};
options.DefaultRequestCulture = new RequestCulture(culture: "en-GB", uiCulture: "en-GB");
options.SupportedCultures = supportedCultures;
options.SupportedUICultures = supportedCultures;
options.RequestCultureProviders = new List<IRequestCultureProvider>
{
new QueryStringRequestCultureProvider(),
new CookieRequestCultureProvider()
};
}).AddRazorPages().
AddViewLocalization()
.AddDataAnnotationsLocalization(options => {
options.DataAnnotationLocalizerProvider = (type, factory) => {
var assemblyName = new AssemblyName(typeof(SharedResource).GetTypeInfo().Assembly.FullName);
return factory.Create("SharedResource", assemblyName.Name);
};
});
services.AddSingleton<ISharedResource, SharedResource>();
}
Configure section
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
app.UseRequestLocalization();
var supportedCultures = new[]
{
new CultureInfo("en-US"),
new CultureInfo("en-GB"),
new CultureInfo("es"),
new CultureInfo("fr")
};
if (env.IsDevelopment()) {
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
} 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.UseRequestLocalization(new RequestLocalizationOptions() {
DefaultRequestCulture = new RequestCulture("en-GB"),
SupportedCultures = supportedCultures,
SupportedUICultures = supportedCultures
});
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints => {
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
Resources Files
Example
The values of the culture at runtime
Just to prove that the cookie is written here.
Why i try to access a static file in my dot net core backend i get
Access to XMLHttpRequest at 'https://localhost:5001/uploads/132248599151771104.jpg' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
And this message in the .net console
CORS policy execution successful.
i've tried
services.AddCors (options => {
options.AddPolicy ("CorsPolicy", builder => {
builder
.AllowAnyOrigin()
.AllowAnyMethod ()
.AllowAnyOrigin()
.AllowAnyHeader ();
});
});
and
app.UseStaticFiles ();
app.UseStaticFiles (new StaticFileOptions {
OnPrepareResponse = ctx => {
ctx.Context.Response.Headers.Append(new KeyValuePair<string, Microsoft.Extensions.Primitives.StringValues>("Access-Control-Allow-Origin", "*"));
ctx.Context.Response.Headers.Append(new KeyValuePair<string, Microsoft.Extensions.Primitives.StringValues>("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"));
},
FileProvider = new PhysicalFileProvider (
Path.Combine (Directory.GetCurrentDirectory (), "Uploads")),
RequestPath = new Microsoft.AspNetCore.Http.PathString ("/Uploads")
});
Startup.cs:
public void ConfigureServices (IServiceCollection services) {
services.AddMvc ().SetCompatibilityVersion (CompatibilityVersion.Version_2_2);
var key = Encoding.ASCII.GetBytes ("this is the secret phrase");
services.AddAuthentication (x => {
x.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
x.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer (x => {
x.RequireHttpsMetadata = false;
x.SaveToken = true;
x.TokenValidationParameters = new TokenValidationParameters {
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey (key),
ValidateIssuer = false,
ValidateAudience = false
};
});
//Enable Cross-Origin Resource Sharing (Front-end and backend on the same server)
services.AddCors (options => {
options.AddPolicy ("CorsPolicy", builder => {
builder
.AllowAnyOrigin()
.AllowAnyMethod ()
.AllowAnyOrigin()
.AllowAnyHeader ();
});
});
services.AddControllers ().AddNewtonsoftJson (options => {
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore;
});
//
services.AddDbContext<DataBaseContext> (options => {
options.UseSqlServer (Configuration.GetConnectionString ("db0"));
});
services.AddControllers ();
services.AddDbContext<RailOpsContext> (options =>
options.UseSqlServer (Configuration.GetConnectionString ("RailOpsContext")));
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure (IApplicationBuilder app, IWebHostEnvironment env) {
app.UseDefaultFiles ();
app.UseStaticFiles ();
app.UseStaticFiles (new StaticFileOptions {
OnPrepareResponse = ctx => {
ctx.Context.Response.Headers.Append(new KeyValuePair<string, Microsoft.Extensions.Primitives.StringValues>("Access-Control-Allow-Origin", "*"));
ctx.Context.Response.Headers.Append(new KeyValuePair<string, Microsoft.Extensions.Primitives.StringValues>("Access-Control-Allow-Headers", "Origin, X-Requested-With, Content-Type, Accept"));
},
FileProvider = new PhysicalFileProvider (
Path.Combine (Directory.GetCurrentDirectory (), "Uploads")),
RequestPath = new Microsoft.AspNetCore.Http.PathString ("/Uploads")
});
// app.UseDirectoryBrowser (new DirectoryBrowserOptions () {
// FileProvider = new PhysicalFileProvider (
// Path.Combine (Directory.GetCurrentDirectory (), #"Uploads")),
// RequestPath = new Microsoft.AspNetCore.Http.PathString ("/Uploads")
// });
app.UseCors ("CorsPolicy");
if (env.IsDevelopment ()) {
app.UseDeveloperExceptionPage ();
}
app.UseHttpsRedirection ();
app.UseRouting ();
app.UseAuthentication ();
app.UseAuthorization ();
app.UseEndpoints (endpoints => {
endpoints.MapControllers ();
});
}
You need to put app.UseCors ("CorsPolicy"); as the first line in Configure method.
I am trying to use asp.net identity framework for mvc and JWT for APIs. Requirement is that api accessing username/device is in the url, for example, api/v1/username/accounts. The user or the device that JWT was issues has username in it. Can I do it in the startup.cs file. The following code was working fine until recently then it started doing strange thing by allowing asp.net identity to use JWT protected APIs. I want to check if username in the url api/v1/username/accounts matches the token one .Following is my code. Thanks for your insights.
public class Startup
{
public Startup(IHostingEnvironment env)
{
var builder = new ConfigurationBuilder()
.SetBasePath(env.ContentRootPath)
.AddJsonFile("appsettings.json", optional: false, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true)
.AddEnvironmentVariables();
Configuration = builder.Build();
Log.Logger = new LoggerConfiguration()
.MinimumLevel
.Warning()
.WriteTo.RollingFile("Logs/GateKeeperLog-{Date}.txt")
.CreateLogger();
}
public static IConfigurationRoot Configuration { get; set; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddSingleton(Configuration);
services.AddDbContext<GkEnterpriseContext>(options =>
options.UseSqlServer(Configuration["Database:Connection"]));
services.AddTransient<IUnitOfWork, UnitOfWork>();
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<GkEnterpriseContext>()
.AddDefaultTokenProviders();
services.AddMvc()
.AddJsonOptions(options =>
{
options.SerializerSettings.Formatting = Formatting.Indented;
}).AddJsonOptions(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
});
services.AddTransient<IEmailSender, AuthMessageSender>();
services.AddTransient<ISmsSender, AuthMessageSender>();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddSerilog();
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseWhen(context => context.Request.Path.Value.Contains("/api")
, builder =>
{
builder.UseJwtBearerAuthentication(new JwtBearerOptions
{
AutomaticAuthenticate = true,
AutomaticChallenge = true,
TokenValidationParameters = new TokenValidationParameters
{
ValidIssuer = Configuration["Tokens:Issuer"],
ValidAudience = Configuration["Tokens:Audidence"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes
(JwtTokenIssuer.PrivateKey)),
ValidateLifetime = true,
NameClaimType = JwtRegisteredClaimNames.FamilyName
}
});
app.UseWhen(context => context.Request.Path.Value.StartsWith("/api/v2/computers/")
, builder1 =>
builder1.MapWhen((ctx) =>
{
var deviceName = ctx.User.Claims.SingleOrDefault(c => c.Type == System.Security.Claims.ClaimTypes.Name)?.Value ?? "";
var testPath = new Microsoft.AspNetCore.Http.PathString($"/api/v2/computers/{deviceName}");
var pathMatch = ctx.Request.Path.StartsWithSegments(testPath);
return String.IsNullOrWhiteSpace(deviceName) || !pathMatch;
}, cfg =>
{
cfg.Run((req) =>
{
req.Response.StatusCode = 403;
return req.Response.WriteAsync("Sorry , you cant access this resource...");
});
}));
});
app.UseIdentity();
app.UseStatusCodePagesWithReExecute("/StatusCodes/{0}");
app.UseStaticFiles();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapRoute(
name: "defaultApi",
template: "api/v2/{controller}/{id?}");
});
}
}
// JWT issung code block, it is now issuing tokens as expected, only validating is the problem.
var claims = new[]
{
new Claim(JwtRegisteredClaimNames.Sub,computer),
new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
new Claim(JwtRegisteredClaimNames.FamilyName,"GkDevice")
};
var key = new SymmetricSecurityKey(
Encoding.UTF8.GetBytes(PrivateKey));
var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
var token = new JwtSecurityToken(
issuer: Startup.Configuration["Tokens:Issuer"],
audience: Startup.Configuration["Tokens:Audidence"],
claims: claims,
notBefore: DateTime.Now,
expires: DateTime.Now.AddYears(10),
signingCredentials: creds
);
var data = new Token
{
Message = "New Token was issued",
Jwt = new JwtSecurityTokenHandler().WriteToken(token),
Iat = GkHelpers.ConvertTimeToEpoch(token.ValidFrom) ,
Exp = GkHelpers.ConvertTimeToEpoch(token.ValidTo)
};
return data;
Something like this might help you --
app.UseWhen(context => context.Request.Path.Value.StartsWith("/api"), builder =>
{
...jwt code...
builder.MapWhen((ctx) =>
{
var userName = ctx.User.Claims.SingleOrDefault(c => c.Type == System.Security.Claims.ClaimTypes.Name)?.Value ?? "";
var testPath = new Microsoft.AspNetCore.Http.PathString($"/api/v2/computers/{userName}/");
var pathMatch = ctx.Request.Path.StartsWithSegments(testPath);
return String.IsNullOrWhiteSpace(userName) || !pathMatch;
}, cfg =>
{
cfg.Run((req) =>
{
req.Response.StatusCode = 403;
return req.Response.WriteAsync("");
});
});
});
The inner MapWhen will trigger when the username in the "Name" claim (configure how to get the username here) does not match the given Path. It will then immediately execute the following request pipeline which will return a 403 code with an empty response body.
I am unsure, however, if you can process Identity-related items in the same request pipeline in which you actually add identity. You might have to extract that MapWhen code outside of the UseWhen.