ASP Net Core 2.1 Session - c#

I am currently developing an API in .Net Core 2.1
with a client application in Vue 2 with Nuxt, and I have problems saving an object in session in ASP .Net.
I have reviewed this and other links before asking this question, but nothing has been able to help me.
It turns out that I've tried it with Postman and if it works, but I do not understand why it does not work with my application.
This is my Startup.cs
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public void ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => false;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
// Add Database
// End Add Database
services.AddCors(options =>
{
options.AddPolicy("AllowSpecificOrigin", builder =>
builder.AllowAnyHeader()
.AllowAnyMethod()
.AllowAnyOrigin()
));
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
.AddDistributedMemoryCache();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromMinutes(1440);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseHsts();
}
app.UseCookiePolicy();
app.UseCors("AllowSpecificOrigin");
app.UseSession();
app.UseMvc();
}
}
In my controller:
[Route("api/customer/[controller]")]
[ApiController]
public class ClientController : ControllerBase { ...
... Get and set Session Var
var model = HttpContext.Session.GetString("User")
And other controller
HttpContext.Session.SetString("User", "Hello World")
HttpContext changes id every time I make a request for ajax, but postman does not change the Id and that's why I can recover the cookie.

You likely need to set the withCredentials flag when making your AJAX request. That shouldn't be required for same-site requests, but you mentioned CORS and didn't specify that it was same-site. With jQuery, that just means adding it to xhrFields in your your AJAX options object:
$.ajax({
...
xhrFields: {
withCredentials: true
}
});
Other libraries may have a different methodology, but all should have some way of setting this flag on the XMLHttpRequest object.

Related

TokenNotFound Message: User not found in token cache. Maybe the server was restarted

I have the following function to call users from active directory use graph api. This function is hit on each keyup of a text box. But i am getting following error
Code: TokenNotFound Message: User not found in token cache. Maybe the server was restarted.
in this line of code
var user = await graphClient.Users.Request().GetAsync();
My class
public class GraphSdkHelper : IGraphSdkHelper
{
private readonly IGraphAuthProvider _authProvider;
private GraphServiceClient _graphClient;
public GraphSdkHelper(IGraphAuthProvider authProvider)
{
_authProvider = authProvider;
}
// Get an authenticated Microsoft Graph Service client.
public GraphServiceClient GetAuthenticatedClient(ClaimsIdentity userIdentity)
{
_graphClient = new GraphServiceClient(new DelegateAuthenticationProvider(
async requestMessage =>
{
// Get user's id for token cache.
var identifier = userIdentity.FindFirst(Startup.ObjectIdentifierType)?.Value + "." + userIdentity.FindFirst(Startup.TenantIdType)?.Value;
// Passing tenant ID to the sample auth provider to use as a cache key
var accessToken = await _authProvider.GetUserAccessTokenAsync(identifier);
// Append the access token to the request
requestMessage.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
// This header identifies the sample in the Microsoft Graph service. If extracting this code for your project please remove.
requestMessage.Headers.Add("SampleID", "aspnetcore-connect-sample");
}));
return _graphClient;
}
}
public interface IGraphSdkHelper
{
GraphServiceClient GetAuthenticatedClient(ClaimsIdentity userIdentity);
}
}
Starup class
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IConfiguration Configuration { get; }
public const string ObjectIdentifierType = "http://schemas.microsoft.com/identity/claims/objectidentifier";
public const string TenantIdType = "http://schemas.microsoft.com/identity/claims/tenantid";
// This method gets called by the runtime. Use this method to add services to the container.
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.AddAuthentication(sharedOptions =>
{
sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
}).AddAzureAd(options => Configuration.Bind("AzureAd", options)).AddCookie();
services.AddControllersWithViews();
services.AddRazorPages();
services.AddDistributedMemoryCache();
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromSeconds(10);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
// Add application services.
//services.AddSingleton<IConfiguration>(Configuration);
services.AddSingleton<IGraphAuthProvider, GraphAuthProvider>();
services.AddTransient<IGraphSdkHelper, GraphSdkHelper>();
//Connection string
services.AddDbContext<PFEContext>(options => options.UseSqlServer(Configuration.GetConnectionString("PFEContext")));
//Group authorization
services.AddAuthorization(options => options.AddPolicy("Customer", policyBuider =>
policyBuider.RequireClaim("groups", "fb721f47-a58c-450a-9fbd-ff13f5960049")));
services.AddAuthorization(options => options.AddPolicy("Developper", policyBuider =>
policyBuider.RequireClaim("groups", "4fad5c4d-9bf9-477b-8814-02dffea5f102")));
services.AddAuthorization(options => options.AddPolicy("ProjectManager", policyBuider =>
policyBuider.RequireClaim("groups", "635b3fff-bb39-4726-8d76-1fef66fb2e8c")));
services.AddAuthorization(options => options.AddPolicy("Tester", policyBuider =>
policyBuider.RequireClaim("groups", "484d8c6c-f458-422f-9e0a-66a971874f3c")));
}
// 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();
app.UseRouting();
app.UseCookiePolicy();
app.UseSession();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapRazorPages();
});
}
}
i need same help to fix this problem , what's going wrong ?
I think that is probably caused by the token that is not well persisting in memory cache,
Otherwise, maybe you are restarting your apps when you close the browser so you need to disable this option in VS because when you restarting the app it's clear all temporary data in memrory .
you can follow these steps disabling this feature:
Go into Tools -> Options, then navigate into Projects and Solutions -> Web Projects and uncheck the option Stop debugger when the browser window is closed.

AuthorizeAttribute does nothing in ASP.NET Core 3 MVC

I have an ASP.NET Core 3.1 MVC project, with a simple authentication system based on cookies, and a few roles and policies. DI is handled with Autofac (not internal DI system of ASP.NET Core).
I know my user is correctly loaded with proper roles, and calls to internal methods like Context.User.IsInRole("Administrator")) (from views) are working as expected.
However, all my AuthorizeAttribute are not working, depending of the content of my Startup whether they seem to do nothing, or I am always redirected to login page (even if the right requirement is fulfilled).
An annotation like
[Authorize(Policy = "Administrator,Collaborator")]
or a simple
[Authorize(Roles = "Administrator")]
placed on an action method seems to do nothing.
I know that order of calls in startup Configure and ConfigureServices matter a lot, but despite many attempts and a lot of reading of similar questions on SO or somewhere else, I was not able to make it work as expected.
I share below my whole Startup file (sorry for that), in hope somebody will be able to point the correct order (or another kind of fix of course), to make it work for my specific case.
Thanks a lot.
public class Startup
{
public Startup(IConfiguration configuration, IWebHostEnvironment environment)
{
Configuration = configuration;
Environment = environment;
}
public IConfiguration Configuration { get; }
public IWebHostEnvironment Environment { get; }
public void ConfigureServices(IServiceCollection services)
{
services.AddControllersWithViews();
services.AddRazorPages();
services.AddOptions();
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options =>
{
options.Cookie.HttpOnly = true;
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Strict;
options.LoginPath = "/Account/Login";
options.SlidingExpiration = true;
options.ExpireTimeSpan = new TimeSpan(0, 24, 0, 0);
options.AccessDeniedPath = "/Error/RightError";
});
services.AddAuthorization(options =>
{
options.AddPolicy(SecurityPolicies.AdministratorOnly, policy =>
policy.RequireClaim(ClaimTypes.Role, UserRoles.Administrator));
options.AddPolicy(SecurityPolicies.AdministratorOrCollaborator, policy =>
policy.RequireClaim(ClaimTypes.Role, UserRoles.Administrator, UserRoles.Collaborator));
});
services.AddSession(options => options.IdleTimeout = TimeSpan.FromHours(4));
services.AddMvc(options => options.Filters.Add(new AuthorizeFilter()))
.AddNewtonsoftJson(options => options.SerializerSettings.ContractResolver = new DefaultContractResolver());
services.AddKendo();
}
// ConfigureContainer is where you can register things directly
// with Autofac. This runs after ConfigureServices so the things
// here will override registrations made in ConfigureServices.
// Don't build the container; that gets done for you by the factory.
public void ConfigureContainer(ContainerBuilder builder)
{
builder.RegisterModule(new MyFrontModule());
}
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseExceptionHandler(ProcessError);
}
else
{
app.UseExceptionHandler("/Error/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseSession();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseCookiePolicy();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
endpoints.MapControllers();
endpoints.MapRazorPages();
});
var ci = new CultureInfo("fr-FR")
{
NumberFormat = { NumberDecimalSeparator = ".", CurrencyDecimalSeparator = "." }
};
app.UseRequestLocalization(new RequestLocalizationOptions
{
DefaultRequestCulture = new RequestCulture(ci),
SupportedCultures = new List<CultureInfo> { ci },
SupportedUICultures = new List<CultureInfo> { ci }
});
}
private void ProcessError(IApplicationBuilder appError)
{
appError.Run(async context =>
{
// Not relevant for my question
});
}
}
I also read that Json Serializer may change something, I am using Newtonsoft with DefaultContractResolver (as above), and I am using Telerik UI components.
Thanks a lot for any useful advice !
As explained in question, I have never been able to have Authorize attribute working as expected, so as my needs in right management were pretty simple, as a workaround I've just implemented a very straightforward FilterAttribute to verify rights based on owned roles.
public class RoleRequirementAttribute : TypeFilterAttribute
{
public RoleRequirementAttribute(params string[] claimValues)
: base(typeof(ClaimRequirementFilter))
{
Arguments = new []{ claimValues.Select(cv => new Claim(ClaimTypes.Role, cv)) };
}
}
public class ClaimRequirementFilter : IAuthorizationFilter
{
readonly IEnumerable<Claim> _claims;
public ClaimRequirementFilter(IEnumerable<Claim> claims)
{
_claims = claims;
}
public void OnAuthorization(AuthorizationFilterContext context)
{
var hasClaim = context.HttpContext.User.Claims.Any(owned => _claims.Any(required => owned.Type == required.Type && owned.Value == required.Value));
if (!hasClaim)
{
context.Result = new ForbidResult();
}
}
}
I resolved this issue by adding .AddRoles<IdentityRole to the identity setting in the startup file.
services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true)
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();

Add session timeout from controller in ASP.NET Core MVC

How to add session timeout from a controller in ASP.NET Core MVC?
I am working on an ASP.NET Core MVC web application, and I need to add the session timeout from my controller's action method.
Configure session in the ConfigureServices
services.AddSession(options =>
{
options.IdleTimeout = TimeSpan.FromSeconds(120);
options.Cookie.HttpOnly = true;
options.Cookie.IsEssential = true;
});
You could try to customize a middleware filter attribute which registers a session, and decorate the controller or the action with this:
public class SessionPipeline
{
public void Configure(IApplicationBuilder applicationBuilder)
{
var options = new SessionOptions
{
IdleTimeout = TimeSpan.FromSeconds(5),
};
applicationBuilder.UseSession(options);
}
}
[MiddlewareFilter(typeof(SessionPipeline))]
public class HomeController : Controller
{
}
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 => false;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddSession();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
//...more middlewares
app.UseSession();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}

Getting Response of Type cors on web api .net core

I'm just trying to return a url to a client i already did all configuration of cors policy but the only return i recieve is of type cors, without any signal of the url that i want to return, the preflight request works fine and the request itself either, the return of my api its my problem.
this is my 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.AddTransient<ITokenManager, TokenManager>();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddSingleton<IAccountService, AccountService>();
services.AddSingleton<ITableauService, TableauService>();
services.AddCors(options =>
{
options.AddPolicy("AllowAll",
builder =>
{
builder
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.Build();
});
});
services.Configure<MvcOptions>(options =>
{
options.Filters.Add(new CorsAuthorizationFilterFactory("AllowAll"));
});
services.AddMvc();
}
// This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
app.UseAuthentication();
app.UseCors("AllowAll");
app.UseMvc();
app.UseStaticFiles();
app.UseCookiePolicy();
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
}
}
fetch api request from client
fetch('https://baseurl?folder=AcompanhamentoComparativoLocaliza&view=DashEmails'
, {
headers: new Headers({
'authorization': 'AuthToken',
'Content-Type':'application/json',
})
})
.then(response => {
console.log('teste',response)
}
)
.catch(error => console.error(error))
this is the output of cors policy, as you guys can see they are executed sucessfully
this is the return in my controller
and now the network in my client
preflight network headers and status
Request itself
response from the api
Thanks in advance, i apreaciate any help.
Response type is cors means
Response was received from a valid cross-origin request. Certain headers and the body may be accessed.
So just get the returned data using :
.then(response => {
response.json().then((data) => {
console.log(data);
})
}
)
In addition , if you want to return url , you should add double quotes ,for example :
return Content("\"https://localhost:8080\"");

.NET Core Model Binding issues

I have an ASP.NET Core controller like this
[ApiController]
public class MADEController : Controller
{
private readonly IRepository _repository;
public MADEController( IRepository repository)
{
_repository = repository;
}
[HttpPost]
[Route("DKAPI/MADE/Update/{tblId}/{recId}")]
public HttpResponseMessage Update(string tblId, string recId, object formParams)
{
var temp = JsonConvert.SerializeObject(HttpContext.Request.Form.ToList());
}
}
If I try to call the Update action via Advanced Rest Client using as Request URL
http://localhost:10356/DKAPI/MADE/Update/32/5
and in the POST Body the following:
[{"Key":"formParams","Value":["[{\"key\":\"id\",\"value\":\"5\"},{\"key\":\"CarRegNo\",\"value\":\"HKK36512\"},{\"key\":\"CarEngSize\",\"value\":\"1234\"},{\"key\":\"DateCreated\",\"value\":\"19/09/2018 00:00\"},{\"key\":\"ExpenseStatus\",\"value\":\"U\"},{\"key\":\"DateCertified\",\"value\":\"\"},{\"key\":\"ClaimFrom\",\"value\":\"10/09/2018\"},{\"key\":\"ClaimTo\",\"value\":\"27/09/2018\"},{\"key\":\"TotalMilesuptothisclaim\",\"value\":\"\"},{\"key\":\"Staff\",\"value\":\"\"}]"]}]
tblId gets value 32, recId gets value 5 BUT the formParams object remains always empty. On the other hand the line
var temp = JsonConvert.SerializeObject(HttpContext.Request.Form.ToList());
prints the above mentioned object. Any ideas why that happens? Am I missing something on Model Binding in .NET Core? It used to work in .NET 4.6 1 but in .NET Core it fails
For convention I add here my startup.cs file.
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)
{
//Database connection
var connectionString = Configuration.GetConnectionString("DBConnectionStringName");
//SOS Add Cors before MVC
services.AddCors();
//Register Repositories
services.AddScoped<IRepository, Repository>();
//The following line is added in order to have access on the HttpContext in controllers
services.TryAddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services
.AddMvc()
.AddWebApiConventions()
.SetCompatibilityVersion(CompatibilityVersion.Version_2_1)
.AddJsonOptions(options =>
{
options.SerializerSettings.ContractResolver = new DefaultContractResolver();
options.SerializerSettings.SerializationBinder = new DefaultSerializationBinder();
});
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressConsumesConstraintForFormFileParameters = true;
options.SuppressInferBindingSourcesForParameters = true;
options.SuppressModelStateInvalidFilter = true;
});
services.AddKendo();
services.AddTransient<IAuthorizationHandler, TokenHandler>();
services.AddAuthorization(options =>
{
options.AddPolicy("Token", policy =>
policy.Requirements.Add(new TokenRequirement()));
});
services.AddAuthentication(options =>
{
options.DefaultChallengeScheme = "DR";
options.AddScheme<DKSchemeHandler>("DR", "DataVision");
});
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
}
app.UseStaticFiles();
app.UseAuthentication();
app.UseOwin();
//SOS Add Cors before MVC
app.UseCors(x => x
.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
app.UseMvc();
}
}
If in the Startup file I remove the lines
services.Configure<ApiBehaviorOptions>(options =>
{
options.SuppressConsumesConstraintForFormFileParameters = true;
options.SuppressInferBindingSourcesForParameters = true;
options.SuppressModelStateInvalidFilter = true;
});
The action is never hit and I get a http 400 bad request error

Categories