Logging in ASP.NET Core 5 - asp.net-core

I have written a project with ASP.NET Core. When I publish the project to the server, my user can not log in for more than 30 minutes, and after 30 minutes, it needs to be re-authenticated and redirected to the login page.
This is my code in the ConfigureServices method:
services.ConfigureApplicationCookie(options =>
{
options.Cookie.HttpOnly = false;
options.LoginPath = "/Login";
options.AccessDeniedPath = "/NotFound";
options.ExpireTimeSpan = TimeSpan.FromDays(30);
options.LogoutPath = "/SignOut";
});
And this is in the Configure method:
app.UseAuthentication();
app.UseAuthorization();
This problem only occurs when the project is published

UPDATE
You can find machine key here. It will help you solve the issue.
Reason
Application generates new machine key every time when it has been restarted. So way to solve problem is to force application to use constant key.
public class Startup
{
public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
Configuration = configuration;
_env = env;
}
public IConfiguration Configuration { get; }
public IWebHostEnvironment _env { get; }
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.SetApplicationName($"my-app-{_env.EnvironmentName}")
.PersistKeysToFileSystem(new DirectoryInfo($#"{_env.ContentRootPath}\keys"));
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)
{
...
}
}
Change FromDays to FromMinutes will help you solve the issue.
options.ExpireTimeSpan = TimeSpan.FromMinutes(30); //TimeSpan.FromDays(30);

Related

Dot Net Core Web API Return Response From Endpoint

I'm busy trying to create a very simple Dot Net Core Web API (Dot Net 5) and I've run into a strange issue where I cannot get the endpoint to return a response.
I've tried to use
await context.Response.WriteAsync("Hello World!");
as per the documentation but I'm getting the error
'HttpResponse' does not contain a definition for 'WriteAsync'
This is the full Startup.cs code
public class Startup {
public Startup(IConfiguration configuration) {
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services) { }
public void Configure(IApplicationBuilder app, IWebHostEnvironment env) {
app.UseRouting();
app.UseEndpoints(endpoints => {
endpoints.MapGet("/test", async context => {
//Console.WriteLine("Exec Test");
await context.Response.WriteAsync("Hello World!");
});
});
}
}
I'm sure there's something I'm missing
Add the dependency for Microsoft.AspNetCore.Http.Abstractions.dll which contains the WriteAsync method you are looking for based on the HttpResponse.
Please refer to the following documentation:
https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.http.httpresponsewritingextensions.writeasync?view=aspnetcore-5.0
https://www.carlrippon.com/asp-net-5-hello-world/

.NET Core Identity and Simple Injector. Crosswire not working

I am using simple injector (4.8.1) on a project that uses asp.net core identity. I tried to crosswise UserManager but I got an error saying
No service for type 'Microsoft.AspNetCore.Identity.UserManager`1[Tenancy.Core.Domain.AppUser]' has been registered."
the SimpleInjectorConfig class is:
public static class SimpleInjectorConfig
{
private static Container _container;
public static void ConfigureServices(IServiceCollection services, IConfiguration config,
IWebHostEnvironment env)
{
_container = new Container();
_container.Options.DefaultScopedLifestyle = new AsyncScopedLifestyle();
_container.ConfigureCore(config, env);
_container.RegisterInitializer<BaseApiController>(controller =>
{
controller.Mediator = _container.GetInstance<IMediator>();
});
services.AddSingleton(_container);
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddControllers();
services.AddLogging();
// Sets up the basic configuration that for integrating Simple Injector with
// ASP.NET Core by setting the DefaultScopedLifestyle, and setting up auto
// cross wiring.
services.AddSimpleInjector(_container, options =>
{
// AddAspNetCore() wraps web requests in a Simple Injector scope and
// allows request-scoped framework services to be resolved.
options
.AddAspNetCore()
.AddControllerActivation();
options.AddLogging();
options.CrossWire<UserManager<AppUser>>();
});
}
public static void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
app.UseSimpleInjector(_container);
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints => { endpoints.MapControllers(); });
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
IdentityModelEventSource.ShowPII = true;
}
//app.UseHttpsRedirection();
_container.Verify();
}
}
and I called it in my Startup.cs file
public class Startup
{
public IConfiguration _configuration { get; }
public IWebHostEnvironment _env { get; }
public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
_configuration = configuration;
_env = env;
}
// This method gets called by the runtime. Use this method to add services to the container.
public void ConfigureServices(IServiceCollection services)
{
SimpleInjectorConfig.ConfigureServices(services, _configuration, _env);
CorsConfig.ConfigureServices(services);
DatabaseConfig.ConfigureServices(services, _configuration);
MvcConfig.ConfigureServices(services);
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
SimpleInjectorConfig.Configure(app, env);
CorsConfig.Configure(app, _configuration);
MvcConfig.Configure(app);
}
}
The configurations have their own class and called in the Startup called in the Startup class just to keep it clean, SimpleInjectorConfig is the config class for simple injector.

.net core not showing HTML static file changes

I made some changes to the static file index.html but running via .net-core and inspecting elements these changes do not apply however when I open the static file via live server extension of vscode I can see the changes.
I am very new to .net core, I looked up a few threads but couldn't find what the problem is or a similar one.
My Startup class looks as so:
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.AddControllers();
services.AddMvc().ConfigureApiBehaviorOptions(options =>
{
options.SuppressConsumesConstraintForFormFileParameters = true;
options.SuppressInferBindingSourcesForParameters = true;
options.SuppressModelStateInvalidFilter = true;
options.SuppressMapClientErrors = true;
options.ClientErrorMapping[404].Link =
"https://httpstatuses.com/404";
});
}
// 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.UseDefaultFiles();
app.UseStaticFiles();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
});
}
}
also, the project repository is here
Thanks to everyone who takes their time to help.

.Net Core 2.x Redirect to Error Page

I have a simple ASP.Net Core 2.0 web application and I have enabled Windows Authentication in project property by enabling Windows Authentication and disabled Anonymous Authentication.
For Authorization at Application/Site level filtering by AD security group, I have the following code in Startup.cs:
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.AddMvc();
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.RequireRole("Application - Administrator")
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseBrowserLink();
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseAuthentication();
//app.UseStatusCodePagesWithRedirects("/Home/Error/{0}");
//app.UseStatusCodePagesWithReExecute("/Home/Error", "?statusCode={0}");
app.UseStatusCodePagesWithReExecute("/Home/Error/{0}");
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
To handle Http 403 status code when a un-authorized user tries to access the application, it will be redirect to a custom error page. So I tried the following 3 approaches in Configure method within Startup.cs:
app.UseStatusCodePagesWithRedirects("/Home/Error/{0}");
app.UseStatusCodePagesWithReExecute("/Home/Error", "?statusCode={0}");
app.UseStatusCodePagesWithReExecute("/Home/Error/{0}");
In the HomeController, I tried both the default Error method
public IActionResult Error()
{
return View(new ErrorViewModel { RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier });
}
and customized one to handle specific status code:
public IActionResult Error(string errCode)
{
if (errCode == "500" || errCode == "404" || errCode == "403")
{
return View($"~/Views/Error/{errCode}.cshtml");
}
return View("~/Views/Shared/Error.cshtml");
}
And I have a simple error page 403.cshtml under /Views/Error/ folder.
But none of them works, all display this page:
I am wondering if something I missed or forgot to implement for display a formatted error page?
Thanks in advance.
I am not 100% sure but there should be 2 variations of windows authentications:
The host only allows authenticated users
When you enable Windows Authentication and disable Anonymous Users
[Authorize] and [AllowAnonymous] no effect, because unauthenticated requests never reach your application
Hence you can't / don't need to set up global filter. You might have to setup the friendly error pages on the server?
public class Startup
{
public IConfiguration Configuration { get; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/home/error");
}
app.UseStaticFiles();
app.UseMvcWithDefaultRoutes();
}
}
The host allows both anonymous and authenticated users
When you enable both Windows Authentication and Anonymous Users
[Authorize] requires additional setup on Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication(IISDefaults.AuthenticationScheme);
services.AddMvc(config =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireRole("Application - Administrator")
.Build();
config.Filters.Add(new AuthorizeFilter(policy));
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
...
app.UseStatusCodePagesWithReExecute("/error", "?code={0}");
app.UseAuthentication();
app.UseMvcWithDefaultRoutes();
}
You need to use [AllowAnonymous] on the error controller to override the [Authorize] global filter to allow anonymous requests.
[AllowAnonymous]
public class ErrorController : Controller
{
public IActionResult Index(int? code)
{
...
}
}
The problem is at the Error method, it missed the AllowAnonymous attribute to allow anonymous access to the error method when the user failed authorization.
Credit to #Calc
Try app.UseStatusCodePagesWithRedirects("/Home/Error/{0}"); in startup.configure(IApplicationBuilder app, IHostingEnvironment env)
Works on ASP.NET CORE2.0 web app
It will handle any kind of HTTP error

Accessing the IHostingEnvironment in ConfigureServices method

I need to check in ConfigureServices method whether the current hosting environment name is 'Development'.
So using IHostingEnvironment.IsDevelopment() method may be ok for me, but unlike in Configure method, I do not have IHostingEnvironment env.
just create a property in the Startup class to persist the IHostingEnvironment. Set the property in the Startup constructor where you already have access, then you can access the property from ConfigureServices
Copied here from question marked as duplicate of this one and deleted. Credit to a-ctor.
If you want to access IHostingEnvironment in ConfigureServices you will have to inject it via the constructor and store it for later access in ConfigureServices:
public class Startup
{
public Startup(IConfiguration configuration, IHostingEnvironment environment)
{
Configuration = configuration;
Environment = environment;
}
public IConfiguration Configuration { get; }
public IHostingEnvironment Environment { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
System.Console.WriteLine($"app: {Environment.ApplicationName}");
}
// rest omitted
}
IHostingEnvironment is deprecated in Core 3.1
private readonly IWebHostEnvironment _env;
public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
_env = env;
Configuration = configuration;
}
should do the trick...
Then reference anywhere with _env.IsDevelopment() etc...
If you aren't using a Startup class and are calling .Configure() directly, you can access the IHostingEnvironment or IWebHostEnvironment using GetService:
ASP.NET Core 2.2:
.Configure(app => {
var hostingEnvironment = app.ApplicationServices.GetService<IHostingEnvironment>();
if (hostingEnvironment?.IsDevelopment() == true)
{
app.UseDeveloperExceptionPage();
}
// .. Other stuff
});
ASP.NET Core 3.x:
.Configure(app => {
var hostingEnvironment = app.ApplicationServices.GetService<IWebHostEnvironment>();
if (hostingEnvironment?.IsDevelopment() == true)
{
app.UseDeveloperExceptionPage();
}
// .. Other stuff
});
If you don't have a Startup class (you may be creating a service) you can get the environment from the hostContext in ConfigureServices like so:
public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureServices((hostContext, services) =>
{
IConfiguration config = hostContext.Configuration;
Configuration = config;
var env = hostContext.HostingEnvironment;
EnvironmentName = env?.EnvironmentName;
...
There are some examples here but none of them seem accurate to the newest release of dotnet, so here we go.
First, in your Startup.cs you should have a reference in your initial constructor like this:
public Startup(IConfiguration configuration, IWebHostEnvironment env)
{
this.Configuration = configuration;
this.Environment = env;
}
We can take the Env and tack it onto ServiceCollection like so:
services.AddSingleton(sp => this.Environment);
Then we can access it in any extension method or other place like so:
var hostEnvironment = services.BuildServiceProvider().GetRequiredService<IHostEnvironment>();
if (hostEnvironment.IsDevelopment())
{
//do something if in dev
}