Identity Server 4 Infinite Loop - c#

I'm working on a asp.net core 2.1 project with identity server 4 installed in it and the users stored in SQL database using entity framework. The Web project has a login page and a dashboard once login is successful.
Please find below the 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)
{
string connectionString = Configuration.GetConnectionString("DefaultConnection");
var migrationsAssembly = typeof(Startup).GetTypeInfo().Assembly.GetName().Name;
services.AddMvc();
services.AddDbContext<ApplicationDbContext>(builder =>
builder.UseSqlServer(connectionString, sqlOptions => sqlOptions.MigrationsAssembly(migrationsAssembly)));
services.AddDbContext<SingleSignOn_dbContext>(builder =>
builder.UseSqlServer(connectionString));
services.AddIdentity<IdentityUser, IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer(options =>
{
options.UserInteraction.LoginUrl = "/Master/Login"; // Set the default login page for Identity server.
}).AddOperationalStore(options =>
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString, sqlOptions => sqlOptions.MigrationsAssembly(migrationsAssembly)))
.AddConfigurationStore(options =>
options.ConfigureDbContext = builder =>
builder.UseSqlServer(connectionString, sqlOptions => sqlOptions.MigrationsAssembly(migrationsAssembly)))
.AddAspNetIdentity<IdentityUser>()
.AddDeveloperSigningCredential();
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().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// 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.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Master/Error");
app.UseHsts();
}
// Only need to run this once.
InitializeDbTestData(app);
app.UseIdentityServer();
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Master}/{action=Login}/{id?}");
});
}
Client Details below in IDS:
new Client {
ClientId = "SingleSignOnInternalClient",
ClientName = "Example Implicit Client Application",
AllowedGrantTypes = GrantTypes.Implicit,
AllowAccessTokensViaBrowser = true,
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email,
"role",
"customAPI.write"
},
AllowedCorsOrigins = new List<string> {"192.168.6.112"},
RedirectUris = new List<string> {"https://localhost:44330/signin-oidc"}, // Configuration.GetSection("TestClient").GetSection("RedirectURL").Value
PostLogoutRedirectUris = new List<string> {"https://localhost:44330"},
RequireConsent = false,
AllowRememberConsent = false,
AccessTokenType = AccessTokenType.Jwt
},
I've created a client project using asp.net core 2.1 and authorize attribute in the contact page (Home controller).
When we clicked on the contact page, it redirects to the Login page of the other project where identity server is installed and when successful user authorization is made. The page is redirected to an infinite loop.
Startup file of client:
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)
{
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
// Use cooking authentication for signing in users.
services.AddAuthentication(options =>
{
options.DefaultScheme = "cookie";
options.DefaultChallengeScheme = "oidc";
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie("cookie")
.AddOpenIdConnect("oidc", options =>
{
options.Authority = Configuration.GetValue<string>("Authority:EndPoint"); //services.Configure<"Authority">(Configuration.GetSection("EndPoint"));
options.ClientId = "SingleSignOnInternalClient";
options.SignInScheme = "cookie";
options.SaveTokens = true;
//options.GetClaimsFromUserInfoEndpoint = true;
options.RequireHttpsMetadata = false;
});
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.AddDbContext<ApplicationDbContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("DefaultConnection")));
services.AddDefaultIdentity<IdentityUser>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddMvc(options =>
{
///options.Filters.Add
}).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
}
// 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.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
Output Log in Client(infinite redirect Loop):
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 POST http://localhost:44330/signin-oidc application/x-www-form-urlencoded 1473
Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler:Information: AuthenticationScheme: cookie signed in.
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 5.4353ms 302
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request starting HTTP/1.1 GET http://localhost:44330/Home/Contact
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Route matched with {action = "Contact", controller = "Home", page = "", area = ""}. Executing controller action with signature Microsoft.AspNetCore.Mvc.IActionResult Contact() on controller IdentityTestClient.Controllers.HomeController (IdentityTestClient).
Microsoft.AspNetCore.Authorization.DefaultAuthorizationService:Information: Authorization failed.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Authorization failed for the request at filter 'Microsoft.AspNetCore.Mvc.Authorization.AuthorizeFilter'.
Microsoft.AspNetCore.Mvc.ChallengeResult:Information: Executing ChallengeResult with authentication schemes ().
Microsoft.AspNetCore.Authentication.OpenIdConnect.OpenIdConnectHandler:Information: AuthenticationScheme: oidc was challenged.
Microsoft.AspNetCore.Mvc.Internal.ControllerActionInvoker:Information: Executed action IdentityTestClient.Controllers.HomeController.Contact (IdentityTestClient) in 8.3527ms
Microsoft.AspNetCore.Hosting.Internal.WebHost:Information: Request finished in 17.5244ms 302
The Url of the infinite loop is below,
https://localhost:44307/connect/authorize?client_id=SingleSignOnInternalClient&redirect_uri=https%3A%2F%2Flocalhost%3A44330%2Fsignin-oidc&response_type=id_token&scope=openid%20profile&response_mode=form_post&nonce=636969892902312620.YzUzMWRiNTktN2Q5Mi00NzZiLWJhMjQtNzEzMjI5Mzk1MTE2ZjM5NWQ2NTEtOTQ4Yi00MDljLWIyYzQtNWE5OTA3YWZkMDFj&state=CfDJ8HSRls71XI5DkQoP2L7ypNS9cYyKsLJm7m1dhd3hXQldeb3Esa0g7uZHU6MiqjlsqTk6h7QaqxXsFuMk05KZfdVdN2qJ9j9v5zVg-BeAFNT5rH_Suq8NUl47VUSfTl6zyrBLxYYgeLn8gfdaQpbmwsynpBuMZ9FR8C8eoVNxyPyQ0nGdBryxybey4QFO1xnwiENQtddWxPexgDBNsAGFNd5l6IYhdHaunWz9Ab7NHS68xdfwORdsNFMJRHtUxAGGhQ08U1WP_-TD2xm1rctVfUFZ_GqoNyc_KDanEmp4AVo5eEF0KgQl6mx4kH0PRMPHeDh3KjZTddKEVQglT0J2Kjo&x-client-SKU=ID_NETSTANDARD1_4&x-client-ver=5.2.0.0
Both the projects have SSL configured to run https locally.
I'm trying to achieve a single sign on solution which has multiple websites in different domain and using the Identity server for login.
Any inputs will be much appreciated.

services.AddDefaultIdentity<IdentityUser>().AddEntityFrameworkStores<ApplicationDbContext>();
is not needed client side.
Beyond the other things, only your IdP should have access to, it re-configures your auth scheme parameters. Anytime you can compare your configuration with the minimum working one from the official repository.

In my case the issue was that both apps (IS4 and my api) were using http. After logging in (and leaving that session open in the browser) I moved both apps to SSL. Then the loop began.
My solution was deleting all the cookies.

Related

SSO Authentication - The oauth state was missing or invalid

I am trying to implement SSO Authentication in ASP.Net Core 3.1 and deploy in Pivot Cloud Foundry(PCF).
In local it's working fine but after deployment getting below error
An unhandled exception occurred while processing the request.
Exception: The oauth state was missing or invalid.
Unknown location
Exception: An error was encountered while handling the remote login.
Microsoft.AspNetCore.Authentication.RemoteAuthenticationHandler.HandleRequestAsync()
HomeController.cs
#if !LOCALTEST
[Authorize]
#endif
public IActionResult Index()
{
string user = "";
if (User.Identity.IsAuthenticated)
{
user = User.Identity.Name;
}
else
{
// WindowsIdentity.GetCurrent
user = WindowsIdentity.GetCurrent().Name.Substring(WindowsIdentity.GetCurrent().Name.LastIndexOf(#"\") + 1);
}
TempData["user"] = user;
return View();
}
Manifest.yml
---
applications:
- name: ApplicationName
memory: 1G
stack: cflinuxfs3
buildpacks:
- dicf_dotnet_core_buildpack_2339_cflinuxfs3
instances: 2
disk_quota: 1G
env:
ASPNETCORE_ENVIRONMENT: Development
GRANT_TYPE: authorization_code
SSO_IDENTITY_PROVIDERS : XXX-sso
SSO_SCOPES : openid,roles,user_attributes
SSO_AUTO_APPROVED_SCOPES : openid,roles,user_attributes
SSO_USERINFO_URL : https://appsso.login.sr3.pcf.xxx.com/userinfo
services :
- serviceName
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
services.AddSession();
services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
services.AddMvc();
services.Configure<MyOptions>(myOptions =>
{
myOptions.ConnString = Configuration.GetConnectionString("DefaultConnection");
});
services
.AddMvc()
.AddJsonOptions(options => options.JsonSerializerOptions.PropertyNamingPolicy = null);
services.AddScoped<IRepository, RepositoryConcrete>();
services.AddControllersWithViews();
services.AddRazorPages();
services.AddCloudFoundryContainerIdentity(Configuration);
services.AddAuthentication((options) =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CloudFoundryDefaults.AuthenticationScheme;
})
.AddCookie((options) =>
{
options.AccessDeniedPath = new PathString("/Home/AccessDenied");
})
.AddCloudFoundryOAuth(Configuration);
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.AddControllersWithViews();
var serviceInfos = CloudFoundryServiceInfoCreator.Instance(Configuration);
var ssoInfo = serviceInfos.GetServiceInfos<SsoServiceInfo>().FirstOrDefault()
?? throw new NullReferenceException("Service info for an SSO Provider was not found!");
userInfoEndPoint = ssoInfo.AuthDomain + "/userinfo";
}
// 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.UseForwardedHeaders(new ForwardedHeadersOptions
{
ForwardedHeaders = ForwardedHeaders.XForwardedProto
});
app.UseSession();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller=Home}/{action=Index}/{id?}");
});
}
Please help me to know what i am missing or required modification.
Thanking in Advance!

how to solve the loop in IdentityServer4 - connect/authorize/callback?client_id=?

hello community I have a project created with asp.net core, blazor webassembly and Identity4, the local project works very well, I published it on an IIS server so that it could be seen from the internet, the project was loaded perfectly, the only detail is that when I enter the login it is loading, until I give it to empty cache and load in a forced way, I can enter the login form, then I enter my credentials and again it stays loading until I empty the cache again and enter the page that indicates I'm already logged in.
How can I enter the login form without emptying the cache and loading
forcefully?
When I click the login button, it sends me to this route but it's wrong:
connect/authorize?client_id=BlazorApp.Client&redirect_uri=https%3A%2F%2
this is the route that is fine to take me:
Identity/Account/Login?ReturnUrl=%2Fconnect%2Fauthorize%2Fcallback%3Fclient_id
this is my class startup:
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
}
public IConfiguration Configuration { get; }
// This method gets called by the runtime. Use this method to add services to the container.
// For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<SimulexContext>
(options => options.UseSqlServer(Configuration.GetConnectionString("SimulexConnection")));
services.AddDefaultIdentity<ApplicationUser>(options => {
options.SignIn.RequireConfirmedAccount = true;
options.Password.RequireDigit = false;
options.Password.RequireLowercase = false;
options.Password.RequireUppercase = false;
options.Password.RequireNonAlphanumeric = false;
})
.AddRoles<IdentityRole>()
.AddEntityFrameworkStores<ApplicationDbContext>();
services.AddIdentityServer()
.AddApiAuthorization<ApplicationUser, ApplicationDbContext>()
.AddProfileService<IdentityProfileService>();
services.AddAuthentication()
.AddIdentityServerJwt();
services.Configure<PayPalConfiguration>(Configuration.GetSection("PayPal"));
services.AddControllersWithViews();
services.AddRazorPages();
services.AddAutoMapper(typeof(Startup));
services.AddScoped<NotificacionesService>();
services.AddScoped<IAlmacenadorDeArchivos, AlmacenadorArchivosLocal>();
services.AddHttpContextAccessor();
services.AddMvc().AddNewtonsoftJson(options =>
options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
}
// 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.UseWebAssemblyDebugging();
}
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.UseHttpsRedirection();
app.UseBlazorFrameworkFiles();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapGet("/api/config/notificacionesllavepublica", async context =>
{
var configuration = context.RequestServices.GetRequiredService<IConfiguration>();
var llavePublica = configuration.GetValue<string>("notificaciones:llave_publica");
await context.Response.WriteAsync(llavePublica);
});
endpoints.MapRazorPages();
endpoints.MapControllers();
endpoints.MapFallbackToFile("index.html");
});
}
}
this is my page appsettingsjson:
"IdentityServer": {
"Key": {
"Type": "Development"
},
"Clients": {
"BlazorApp.Client": {
"Profile": "IdentityServerSPA"
}
}
},
Can you share your startup for the blazor app?
I had the same issue a couple weeks ago but with an asp.net mvc app when integrating is4 with which had identity configured. So it could be same for you.
Enet's solution might work, but I have not tried it. Below is another solution which worked for me only if you have Identity configured in your Blazor app. Try setting the schemes in your services.AddAuthentication and AddOpenIdConnect:
services.AddAuthentication(options =>
{
options.DefaultScheme = "Cookies";
options.DefaultChallengeScheme = "Oidc";
options.DefaultAuthenticateScheme = "Cookies"; // <-- add this line
})
.AddCookie("Cookies", options =>
{
})
.AddOpenIdConnect("oidc", options =>
{
options.SignInScheme = "Cookies"; // <-- add this line
})
;

Microsoft Identity Authorize

In my application I'm using Microsoft Identity Authorize to load an AspNet Core view and require the user credentials to access the page.
My problem is that IIS Express executing throug VS 2019, works just fine but when I publish it on IIS (both problem in self-dependent / self-contained) every time that I made a request to access the view it ask me to make the login over and over again.
My Startup.cs file:
namespace SistemaGestor.SOO.Mvc
{
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<SOOContext>(srv => SOOContextFactory.CreateInstance(Configuration));
//Fernando Milanez 25/09/2019
services.AddTransient<IEmbarcacaoInterface,EmbarcacaoRepositorio>();
services.AddTransient<IBandeiraInterface, BandeiraRepositorio>();
services.AddTransient<IAutenticacao, AutenticacaoRepositorio>();
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(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
}).AddCookie(options =>
{
options.LoginPath = "/Autenticacao/Login";
options.ExpireTimeSpan = TimeSpan.FromMinutes(20);
});
services.AddSession(options =>
{
options.Cookie.IsEssential = true;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2)
.AddSessionStateTempDataProvider();
}
// 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.UseDeveloperExceptionPage();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
RequestLocalizationOptions localizationOptions = new RequestLocalizationOptions
{
SupportedCultures = new List<CultureInfo> { new CultureInfo("pt-BR") },
SupportedUICultures = new List<CultureInfo> { new CultureInfo("pt-BR") },
DefaultRequestCulture = new RequestCulture("pt-BR")
};
app.UseRequestLocalization(localizationOptions);
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseSession();
app.UseAuthentication(); //Requisito para ativar a autenticao, então é sempre assim adiciono o middlewaree depois defino para usar
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
});
}
}
}
In my Controller, I've input the [Authorize] attribute:
namespace SistemaGestor.SOO.Mvc
{
[Authorize]
//logical code below
}
I didn't post any error message because it does not show any error.

Cookie not expiring per StartUp.cs settings

I have tried a plethora of solutions over the course of 2 days and still have not been able to get this to work. What I want is for a user cookie to expire after a set amount of time
E.g. User A logs in and goes to home page, User A goes for a lunch break. User A comes back and clicks on the nav bar and gets redirected to the login page.
I have tried everything from AddAuthentication(), AddSession() and AddCookie() options all having an ExpireTimeSpan and Cookie.Expiration of my choosing. Nothing seems to work. The project uses ASP.NET Identity and I am aware this service should be called before the cookie options. Please see my current StartUp.cs below, this is the last thing i tried:
Startup.cs
public class Startup
{
public IConfiguration Configuration { get; }
public IContainer ApplicationContainer { get; private set; }
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}
public IServiceProvider ConfigureServices(IServiceCollection services)
{
services.Configure<CookiePolicyOptions>(options =>
{
options.CheckConsentNeeded = context => false;
options.MinimumSameSitePolicy = SameSiteMode.None;
});
services.AddIdentity<ApplicationUser, IdentityRole>(config =>
{
config.SignIn.RequireConfirmedEmail = true;
})
.AddDefaultTokenProviders()
.AddEntityFrameworkStores<ApplicationDbContext>();
//other services e.g. interfaces etc.
services.AddAuthentication().AddCookie(options =>
{
options.Cookie.HttpOnly = true;
options.Cookie.Expiration = TimeSpan.FromSeconds(60);
options.LoginPath = "/Account/Login";
options.LogoutPath = "/Account/Logout";
options.AccessDeniedPath = "/AccessDenied";
options.ExpireTimeSpan = TimeSpan.FromSeconds(5);
options.SlidingExpiration = true;
});
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_1);
//services.AddSession();
var containerBuilder = new ContainerBuilder();
containerBuilder.Populate(services);
this.ApplicationContainer = containerBuilder.Build();
var serviceProvider = new AutofacServiceProvider(this.ApplicationContainer);
return serviceProvider;
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseDatabaseErrorPage();
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.ConfigureCustomExceptionMiddleware();
app.UseStaticFiles();
app.UseCookiePolicy();
app.UseAuthentication();
//app.UseSession();
app.UseMvc();
}
}
The following code isn't affecting the Identity cookie:
services.AddAuthentication().AddCookie(options => ...);
Instead, it's adding a new cookie-based authentication scheme, named Cookies, and configuring that. With all the standard Identity setup, this scheme is unused, so any changes to its configuration will have no effect.
The primary authentication scheme used by Identity is named Identity.Application and is registered inside of the AddIdentity<TUser, TRole> method in your example. This can be configured using ConfigureApplicationCookie. Here's an example:
services.ConfigureApplicationCookie(options => ...);
With that in place, the cookie options will be affected as intended, but in order to set a cookie with a non-session lifetime, you also need to set isPersistent to true inside your call to PasswordSignInAsync. Here's an example:
await signInManager.PasswordSignInAsync(
someUser, somePassword, isPersistent: true, lockoutOnFailure: someBool);

Cross domain request in asp.net signalr core does not work?

I am working on asp.net core signalr 1.1.0 under asp.net core 2.2 version. I want to
make the cross-domain request for web client and as well as a mobile client.
When I send request from javascript client, then this request blocked, and below error shows,
(index):1 Access to XMLHttpRequest at 'https://localhost:44373/chatHub/negotiate?token=12' from origin 'https://localhost:44381' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: The value of the 'Access-Control-Allow-Origin' header in the response must not be the wildcard '*' when the request's credentials mode is 'include'. The credentials mode of requests initiated by the XMLHttpRequest is controlled by the withCredentials attribute.
My Javascript client code
var connection = new signalR.HubConnectionBuilder().withUrl("https://localhost:44373/chatHub?token="+12).build();
Signalr core service startup class code
// 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.AddCors(options =>
{
options.AddPolicy("CorsPolicy",
builder => builder.AllowAnyOrigin()/*WithOrigins("https://localhost:44381")*/
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials());
});
services.AddSignalR();
services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
//services.AddCors();
}
// 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.UseDeveloperExceptionPage();
}
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.UseHttpsRedirection();
app.UseCors("CorsPolicy");
app.UseSignalR(routes =>
{
routes.MapHub<ChatHub>("/chatHub");
});
//app.UseStaticFiles();
//app.UseCookiePolicy();
app.UseMvc();
}
builder.AllowAnyOrigin() its not working
builder => builder.WithOrigins("https://localhost:44381") its worked, but this is specific for this origin ,
I want to make AllowAnyOrigin()??
I got it working this way
On Configure services at the top
services.AddCors();
and in the Configure method
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
.AddDbContext<ChatContext>(options => options.UseSqlServer(Configuration.GetConnectionString("DefaultConnection")));
services.Configure<FormOptions>(options =>
{
options.MultipartBodyLengthLimit = 60000000;
});
services.AddMvc().AddJsonOptions(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});
services.AddMvcCore()
.AddAuthorization()
.AddJsonOptions(options =>
{
options.SerializerSettings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
options.SerializerSettings.ContractResolver = new CamelCasePropertyNamesContractResolver();
});
var identityServerAuthOptions = Configuration.GetSection("Identity").Get<IdentityServerAuthenticationOptions>();
services.AddAuthentication("Bearer")
.AddIdentityServerAuthentication(options =>
{
options.Authority = identityServerAuthOptions.Authority;
options.RequireHttpsMetadata = identityServerAuthOptions.RequireHttpsMetadata;
options.ApiName = identityServerAuthOptions.ApiName;
});
var settings = new JsonSerializerSettings();
settings.ReferenceLoopHandling = ReferenceLoopHandling.Ignore;
settings.ContractResolver= new CamelCasePropertyNamesContractResolver();
services.AddSignalR()
.AddJsonProtocol(options => {
options.PayloadSerializerSettings = settings;
});
services.AddTransient<IUserService, UserService>();
services.AddCors();
}
public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
loggerFactory.AddConsole(Configuration.GetSection("Logging"));
loggerFactory.AddDebug();
//Data.AddData(app.ApplicationServices.GetService<ChatContext>());
app.Use(async (context, next) =>
{
if (string.IsNullOrWhiteSpace(context.Request.Headers["Authorization"]))
{
if (context.Request.QueryString.HasValue)
{
var token = context.Request.QueryString.Value.Split('&').SingleOrDefault(x => x.Contains("authorization"))?.Split('=')[1];
if (!string.IsNullOrWhiteSpace(token))
{
context.Request.Headers.Add("Authorization", new[] { $"Bearer {token}" });
}
}
}
await next.Invoke();
});
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
// app.UseBrowserLink();
}
else
{
app.UseExceptionHandler("/Home/Error");
}
app.UseStaticFiles();
app.UseAuthentication();
app.UseCors(x => x.AllowAnyOrigin().AllowAnyHeader().AllowAnyMethod().AllowCredentials());
app.UseSignalR(config =>
{
config.MapHub<UserHub>("/UsersHub");
});
app.UseMvc(routes =>
{
routes.MapRoute(
name: "default",
template: "{controller=Home}/{action=Index}/{id?}");
routes.MapSpaFallbackRoute("spa-fallback", new { controller = "Home", action = "Index" });
});
}
}
app.UseCors(builder =>
builder.AllowAnyOrigin()
.AllowAnyMethod()
.AllowAnyHeader()
);
Whole code can be found here. This used to work just fine for me. I haven't opened it lately though
Github Repo
I see two issues with your code. Let's tackle them one by one.
Allowing all origins for the entire application even though you need it only for the SignalR connection. Consider the below code if you want to apply CORS policy only for the signalR endpoint
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapHub<UsersHub>("/UsersHub")
.RequireCors((policyBuilder) => policyBuilder
.WithOrigins("clientUrls")
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
});
It is recommended to not allow all origins but if you have such a use case then the below workaround can fix your problem. This is the trick of using .SetIsOriginAllowed(_ => true)
.SetIsOriginAllowed(_ => true)
.AllowAnyMethod()
.AllowAnyHeader()
.AllowCredentials()
Further if you want more information, have a look at this guide for more details.

Categories

Resources