Wkhtmltopdf rotativa ASP.NET Core MVC issue - c#

I am using a digital ocean droplet using Ubuntu 18.04 LTS and deployed my ASP.NET Core 5.0 MVC project on it and everything works great. I was trying to install rotativa on it to print pdf documents but I cannot make this work.
I followed these steps: https://blog.elmah.io/generate-a-pdf-from-asp-net-core-for-free/
But I am getting this error when trying to print the pdf:
Exception: QPainter::begin(): Returned false Exit with code 1, due to unknown error.
I have this in my Startup.cs:
using Wkhtmltopdf.NetCore;
namespace farmamest
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
// services.AddControllersWithViews();
services.AddRazorPages();
services.Configure<ForwardedHeadersOptions>(options =>
{
options.KnownProxies.Add(IPAddress.Parse("10.0.0.100"));
});
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = false)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<Context>();
services.AddControllersWithViews();
services.Configure<IdentityOptions>(options =>
{
// Password settings.
options.Password.RequireDigit = false;
options.Password.RequireLowercase = false;
options.Password.RequireNonAlphanumeric = false;
options.Password.RequireUppercase = false;
options.Password.RequiredLength = 6;
options.Password.RequiredUniqueChars = 1;
// Lockout settings.
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(15);
//options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.AllowedForNewUsers = true;
// Default SignIn settings.
options.SignIn.RequireConfirmedEmail = false;
options.SignIn.RequireConfirmedPhoneNumber = false;
// User settings.
options.User.AllowedUserNameCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._#+";
options.User.RequireUniqueEmail = true;
});
services.ConfigureApplicationCookie(options =>
{
// Cookie settings
// options.Cookie.Name = Configuration["CookieName"];
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
options.LoginPath = "/Identity/Account/Login";
options.AccessDeniedPath = "/Identity/Account/AccessDenied";
options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
options.SlidingExpiration = true;
});
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
// options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddMvc(config =>
{
// var policy = new AuthorizationPolicyBuilder()
// .RequireAuthenticatedUser()
// .Build();
// config.Filters.Add(new AuthorizeFilter(policy));
});
services.Configure<PasswordHasherOptions>(option =>
{
option.IterationCount = 12000;
});
services.AddWkhtmltopdf("Rotativa");
}
// 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();
// app.UseMigrationsEndPoint();
}
else
{
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.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedFor | ForwardedHeaders.XForwardedProto
});
app.UseHttpsRedirection();
app.UseStaticFiles();
//cookie policy
app.UseCookiePolicy();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseDefaultFiles();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
}
}
I saved the files in <foldername>/<projectname>/bin/Debug/net5.0/Rotativa
How do I make this work? Is this version of net issue related? I am using net5.0, I cant find solutions in the web, I got headaches.

It's an issue with .NET 5. Looks related to the invoking Wkhtmltopdf.
https://github.com/fpanaccia/Wkhtmltopdf.NetCore/issues/46

Related

How to configure IIS from a webapi that was in net3.1 in net7.0

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();

Invalid Authentication method, invalid client error when trying to connect with OIDC

We're trying to develop an ASP Net application, and we have to use an oidc authentication system.
we've got our own OIDC server. When we try to connect we've got an error message :
"System.Exception: An error was encountered while handling the remote login.
---> Microsoft.IdentityModel.Protocols.OpenIdConnect.OpenIdConnectProtocolException: Message contains error: 'invalid_client', error_description: 'Invalid authentication method for accessing this endpoint.', error_uri: 'error_uri is null'."
here is our ConfigureService function and Configure function:
public void ConfigureServices(IServiceCollection services)
{
IdentityModelEventSource.ShowPII = true;
ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls13 | SecurityProtocolType.Tls12 | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls;
services.AddMvc();
services.AddOptions();
SetGlobalConfig();
services.AddHttpContextAccessor();
services.AddResponseCompression(options =>
{
options.Providers.Add<BrotliCompressionProvider>();
options.Providers.Add<GzipCompressionProvider>();
options.EnableForHttps = true;
});
services.AddAntiforgery(options =>
{
options.Cookie.Name = "X-CSRF-TOKEN-OurAppli";
options.HeaderName = "X-CSRF-TOKEN-OurAppli";
options.FormFieldName = "X-CSRF-TOKEN-OurAppli";
});
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(5);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
options.Cookie.SecurePolicy = Microsoft.AspNetCore.Http.CookieSecurePolicy.Always;
});
services.AddDetection();
services.AddControllersWithViews();
var identityUrl = Configuration.GetValue<string>("IdentityUrl");
var bearerUrl = Configuration.GetValue<string>("BearerUrl");
var callBackUrl = Configuration.GetValue<string>("CallBackUrl");
var sessionCookieLifetime = Configuration.GetValue("SessionCookieLifetimeMinutes", 60);
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(setup => setup.ExpireTimeSpan = TimeSpan.FromMinutes(sessionCookieLifetime))
.AddOpenIdConnect(options =>
{
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.ResponseType = "code";
options.ClientId = "*******";
options.ClientSecret = "********";
options.Authority = "https://ourOIDCServer/ourOIDCServerwebsso/oauth2/multiauth";
options.GetClaimsFromUserInfoEndpoint = true;
options.Scope.Clear();
options.Scope.Add("openid uid isMemberOf");
options.SaveTokens = true;
options.Configuration = new OpenIdConnectConfiguration
{
AuthorizationEndpoint = "https://ourOIDCServer/ourOIDCServerwebsso/oauth2/multiauth/authorize",
TokenEndpoint = "https://ourOIDCServer/ourOIDCServerwebsso/oauth2/multiauth/access_token",
UserInfoEndpoint = "https://ourOIDCServer/ourOIDCServerwebsso/oauth2/multiauth/userinfo",
EndSessionEndpoint = "https://ourOIDCServer/ourOIDCServerwebsso/oauth2/multiauth/connect/endSession",
RegistrationEndpoint = "https://ourOIDCServer/ourOIDCServer/oauth2/multiauth/connect/register",
JwksUri = "ourOIDCServer/ourOIDCServer/oauth2/multiauth/connect/jwk_uri",
};
options.Events = new OpenIdConnectEvents
{
OnRedirectToIdentityProvider = context =>
{
context.ProtocolMessage.SetParameter("acr_values","ourACR");
context.ProtocolMessage.SetParameter("authlevel", "3");
var byteArray = Encoding.ASCII.GetBytes(options.ClientId + ":" + options.ClientSecret);
context.Request.Headers.Add("Authorization", "Post " + byteArray);
return Task.FromResult(0);
}
};
});
services.AddHsts(options =>
{
options.Preload = true;
options.IncludeSubDomains = true;
options.MaxAge = TimeSpan.FromDays(365);
});
}
public void Configure(IApplicationBuilder app, IHostEnvironment 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();
app.UseResponseCompression();
app.UseDetection();
app.UseSession();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.Use(async (context, next) =>
{
context.Response.Headers.Add("X-Frame-Options", "DENY");
context.Response.Headers.Add("Content-Security-Policy", "default-src 'self'; font-src 'self';script-src 'self' 'unsafe-inline' 'unsafe-eval'; connect-src 'self'; img-src 'self'; style-src 'self' 'unsafe-inline'");
await next();
});
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "Index",
pattern: "{controller=Home}/{action=Index}");
});
app.UseStaticFiles();
}`
And there is our HomeController :
[Authorize]
public ActionResult Index()
{
Console.WriteLine(_user);
Console.WriteLine(_habilitation);
dynamic models = new ExpandoObject();
models.detection = _detectionService;
if (!string.IsNullOrEmpty(_user) || _user != "")
{
models.Authorization = _habilitation;
models.Name = _user;
Console.WriteLine(models.Name + " Auth= " + models.Authorization);
models.Habilitation = 1;
}
return View("Index", models);
}
I never used an OIDC authentication system with ASP Net so i don't know if there is something wrong with my code...
Hope someone can help me!
Can you add to the question how the client is defined? What OIDC provider are you using?
The problem seems that the client asks for "authorization code flow" here:
options.ResponseType = "code";
but the OIDC provider does not have that enabled. I would check that first.

User.Identity is always null

I need to check if an user is logged in or not. In View I'm checking it like this;
#if (User.Identity.IsAuthenticated)
{
//links...
}
else
{
//links...
}
always returns false and Identity is empty although I SignInAsync in my login function. I tried to change the order of the configure method usings but it didn't work.
Here is my startup and login function.
public void ConfigureServices(IServiceCollection services)
{
var key = Encoding.ASCII.GetBytes(Configuration.GetSection("Appsettings:Secret").Value);
services.AddDbContext<BiHaberContext>();
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<BiHaberContext>()
.AddDefaultTokenProviders();
services.Configure<IdentityOptions>(options =>
{
options.Password.RequireDigit = false;
options.Password.RequiredLength = 3;
options.Password.RequireLowercase = false;
options.Password.RequireUppercase = false;
options.Password.RequireNonAlphanumeric = false;
options.Lockout.MaxFailedAccessAttempts = 3;
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.User.RequireUniqueEmail = false;
options.SignIn.RequireConfirmedEmail = false;
options.SignIn.RequireConfirmedPhoneNumber = false;
options.SignIn.RequireConfirmedAccount = false;
});
services.AddAutoMapper(typeof(Startup));
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key),
ValidateIssuer = false,
ValidateAudience = false
};
});
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
//options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromDays(30);
options.LoginPath = "/Login";
options.AccessDeniedPath = "/Identity/Account/AccessDenied";
options.SlidingExpiration = true;
});
services.AddAuthentication();
services.AddAuthorization();
services.AddControllersWithViews();
services.AddScoped<ISemesterService, SemesterManager>();
services.AddScoped<IDepartmentService, DepartmentManager>();
services.AddScoped<ICourseService, CourseManager>();
services.AddScoped<IAnnouncementService, AnnouncementManager>();
services.AddCors();
services.AddResponseCaching();
services.AddMemoryCache();
}
// 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");
app.UseHsts();
}
app.UseCors(x => x.AllowAnyHeader().AllowAnyOrigin().AllowAnyHeader());
app.UseResponseCaching();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCookiePolicy();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}");
});
}
Login:
[HttpPost("/login")]
public async Task<IActionResult> Login(LoginModel model)
{
if (!ModelState.IsValid)
return View(model);
var myContent = JsonConvert.SerializeObject(model);
var stringContent = new StringContent(myContent, System.Text.Encoding.UTF8, MediaTypeNames.Application.Json);
using (var postTask = await ApiHelper.ApiClient.PostAsync("Auth/Login", stringContent))
{
string jwt = await postTask.Content.ReadAsStringAsync();
var handler = new JwtSecurityTokenHandler();
var token = handler.ReadJwtToken(JwtExtension.CorrectJwtFormat(jwt));
var claims = token.Payload.Claims.ToList();
var claimsIdentity = new ClaimsIdentity(
claims, CookieAuthenticationDefaults.AuthenticationScheme);
var authProperties = new AuthenticationProperties()
{
AllowRefresh = true, ExpiresUtc = DateTimeOffset.Now.AddMonths(1), IsPersistent = true
};
await HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,
new ClaimsPrincipal(claimsIdentity),authProperties);
return RedirectToAction("index", "home");
}
}
API works well and brings me 7 claims and claimsIdentity contains them as well. And redirecting to index. What did I do wrong I just couldn't figure out.
Added: Also I can not use Authorize attribute. So there is no authorizing anywhere.
When I delete this line
services.AddIdentity<ApplicationUser, ApplicationRole>()
.AddEntityFrameworkStores<BiHaberContext>();
It worked. Identity is overriding my own claims. Thanks to #David Liang

dotnet core authorize always redirect to identity default login page

I create custom login page in pages/login.cshtml, and also i set [authorize] config in startup.cs to redirect to /login, but it keep redirect to Identity/Account/Login.
this is my startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
// This lambda determines whether user consent for non-essential cookies is needed for a given request.
options.CheckConsentNeeded = context => true;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>()
.AddDefaultTokenProviders();
services.Configure<IdentityOptions>(options =>
{
// Password settings.
options.Password.RequireDigit = true;
options.Password.RequireLowercase = true;
options.Password.RequireNonAlphanumeric = true;
options.Password.RequireUppercase = true;
options.Password.RequiredLength = 6;
options.Password.RequiredUniqueChars = 1;
// Lockout settings.
options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
options.Lockout.MaxFailedAccessAttempts = 5;
options.Lockout.AllowedForNewUsers = true;
// User settings.
options.User.AllowedUserNameCharacters =
"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._#+";
options.User.RequireUniqueEmail = false;
});
services.ConfigureApplicationCookie(options =>
{
// Cookie settings
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromMinutes(5);
options.LoginPath = "/Login";
options.AccessDeniedPath = "/AccessDenied";
options.LogoutPath = "/Logout";
options.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
options.SlidingExpiration = true;
});
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddRazorPagesOptions(options =>
{
options.Conventions.AddPageRoute("/Dashboards/Dashboard1", "");
options.Conventions.AllowAnonymousToPage("/Login");
});
}
I already specify loginpath = "/login", but it always back to identity default page, why and how to solve it?
For this issue, try services.PostConfigure<CookieAuthenticationOptions> like
services.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddMvc()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddRazorPagesOptions(options =>
{
options.Conventions.AddPageRoute("/Dashboards/Dashboard1", "");
options.Conventions.AllowAnonymousToPage("/Login");
});
services.PostConfigure<CookieAuthenticationOptions>(IdentityConstants.ApplicationScheme,
opt => {
//configure your other properties
opt.LoginPath = "/Login";
});

How to manually validate JWT based on username in the url asp.net core

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.

Categories

Resources