Issue
So I have a frontend/SPA in Angular
and a backend/API in ASP.NET Core 5
. After building the frontend, the build files were copied to the backend's wwwroot folder.
I implemented an authentication flow with OpenIDConnect in my backend. This is triggered by the frontend and leads to a backend endpoint. So you will be redirected to the Identity Provider and back to the callback endpoint that ASP.NET provides.
Now when I open the website, ASP.NET serves me the static Angular files and this redirects me to the Endpoint which starts the Login/Auth process. The process end up redirecting me to https://localhost:5001/callback
.
The problem now is that ASP.NET is not serving the request through the pre-configured callback
path. It will forward the request to the static files so Angular will process the request.
So my question is: Is it possible to exclude specific paths so that they are processed via ASP.NET instead of the static files?
So far I've tried intercepting the request and only forwarding what doesn't have /api or /callback in the path. As described in these blogs/questions:
- https://www.blinkingcaret.com/2018/01/24/angular-and-asp-net-core/
- https://weblog.west-wind.com/posts/2020/Jul/12/Handling-SPA-Fallback-Paths-in-a-Generic-ASPNET-Core-Server
- My SPA files are giving 404 errors when serving the SPA in a branch of the request pipeline. How do I make my static files available to my SPA?
ConfigureServices
in my Startup.cs
looks like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddControllers();
services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new OpenApiInfo { Title = "backend", Version = "v1" });
});
JwtSecurityTokenHandler.DefaultInboundClaimTypeMap.Clear();
services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
})
.AddCookie(options =>
{
options.Cookie.SecurePolicy = CookieSecurePolicy.Always;
options.Cookie.SameSite = SameSiteMode.Strict;
options.Cookie.HttpOnly = true;
options.ExpireTimeSpan = TimeSpan.FromHours(2);
options.SlidingExpiration = true;
options.Cookie.MaxAge = TimeSpan.FromHours(2);
})
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options => ConfigureOpenIdConnect(options));
services.AddControllersWithViews();
services.AddSpaStaticFiles(configuration =>
{
configuration.RootPath = "wwwroot";
});
services.AddCors(options =>
{
options.AddDefaultPolicy(builder =>
{
builder.AllowAnyOrigin();
builder.AllowAnyHeader();
builder.AllowAnyMethod();
});
});
}
My Configure
looks like this:
public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
if (env.IsDevelopment())
{
app.UseDeveloperExceptionPage();
app.UseSwagger();
app.UseSwaggerUI(c => c.SwaggerEndpoint("v1/swagger.json", "backend v1"));
}
else
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseCors();
app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapControllerRoute(
name: "default",
pattern: "{controller}/{action}/{id?}");
});
app.UseDefaultFiles();
app.UseStaticFiles();
app.UseSpa(spa =>
{
spa.Options.SourcePath = "../../frontend/";
if (env.IsDevelopment())
{
spa.UseAngularCliServer(npmScript: "dev:start");
}
});
}
private void ConfigureOpenIdConnect(OpenIdConnectOptions options)
{
options.Authority = Configuration.GetValue<string>("Authority");
options.ClientId = Configuration.GetValue<string>("ClientId");
options.ClientSecret = Configuration.GetValue<string>("ClientSecret");
// Set response type to code
options.ResponseMode = OpenIdConnectResponseMode.FormPost;
// Configure the scope
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("offline_access");
options.CallbackPath = new PathString("/callback");
// This saves the tokens in the session cookie
options.SaveTokens = true;
options.UseTokenLifetime = false;
}
Update 1:
folder structure of the ASP.NET project
:
folder structure of wwwroot
:
these are the Angular build files.
In the assets
folder is the font and some images
Solution
Ok I found the solution to the problem. What I didn't notice before was that I was getting an HTTP 200 code for the callback route. Normally you would probably get an HTTP 302 for a redirect.
In the end, it turned out that the service worker from the Angular PWA
interrupted the request. I don't really know why, but when I removed the ServiceWorker
from app.module.ts
, it worked again.
Answered By - Layton
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.