简体   繁体   中英

Securing Blazor WASM and API with Auth0. CORS Policy issue

I've been following the tutorial at Auth0 for securing a Blazor WASM and API with Aut0, which is found here --> https://auth0.com/blog/securing-blazor-webassembly-apps/

Securing the app works fine, but adding the API gives me issues. As soon as I add the authenticate attribute to the API Controller it results in this:

fetchdata:1 Access to fetch at 'https://localhost:7226/weatherforecast' from origin 'https://localhost:7298' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.

I've added a policy to allow the app in the program.cs

builder.Services.AddCors(options =>
{
  options.AddPolicy("Open", builder => builder.WithOrigins("https://localhost:7298").AllowAnyMethod().AllowAnyHeader());
});

I've played around with the program.cs and also added app.UseCors before authentication/authorization (as a provided solution I found online), which then results in another issue.

Failed to load resource: the server responded with a status of 401 ()

blazor.webassembly.js:1 crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100] Unhandled exception rendering component: The input does not contain any JSON tokens. Expected the input to start with a valid JSON token, when isFinalBlock is true. Path: $ | LineNumber: 0 | BytePositionInLine: 0. System.Text.Json.JsonException: The input does not contain any JSON tokens. Expected the input to start with a valid JSON token, when isFinalBlock is true. Path: $ | LineNumber: 0 | BytePositionInLine: 0.

That error seems to indicate an issue with the bearertoken not being set, but it is setup using BaseAddressAuthorizationMessageHandler.

builder.Services.AddHttpClient("APIClient", client =>
{
  client.BaseAddress = new Uri("https://localhost:7226");
  client.DefaultRequestHeaders.Clear();
  client.DefaultRequestHeaders.Add(HeaderNames.Accept, "application/json");
}).AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

I've added the project to GitHub, if more details on the code is of interest https://github.com/obrungot/BlazorAuthenticationPlayGround.git

AddCors doesn't actually do anything except for adding a policy. It's not using that policy until you specify it somewhere. You can specify a global policy by using app.UseCors("Open") , add the policy to the endpoint routing eg app.MapGet("/test", () => Results.Ok("test")).RequireCors("Open") or for controllers by using an attribute like [EnableCors("Open")] .

That you received a 401 suggested that Cors in general seems to work, however Cors also needs explicit permission to keep the Authorization header. This is done by adding "AllowCredentials()" to the policy like this:

builder.Services.AddCors(options =>
{
    options.AddPolicy("Open", builder => builder
        .WithOrigins("https://localhost:7298")
        .AllowAnyMethod()
        .AllowAnyHeader()
        .AllowCredentials()
    );
});

I hope this helps!


Edit:

Sorry. I somehow missed the github repository link. The reason why it doesn't work is that BaseAddressAuthorizationMessageHandler is meant for hosting the API within the BaseAddress of the app. So in your case only calls to https://localhost:7298/ will include the token. You might either choose to host the API together with the app in the same process (this can be set up by choosing "ASP.NET Core Hosted" in the template) or use a custom AuthorizationMessageHandler which you can learn about here https://learn.microsoft.com/en-us/as.net/core/blazor/security/webassembly/additional-scenarios?view=as.netcore-7.0#custom-authorizationmessagehandler-class

In your case this would look like this:

public class ApiAuthorizationMessageHandler : AuthorizationMessageHandler
{
    public ApiAuthorizationMessageHandler(IAccessTokenProvider provider, NavigationManager navigationManager) : base(provider, navigationManager)
    {
        ConfigureHandler(new[] { "https://localhost:7226" });
    }
}

When it comes to the cors the order is important

app.UseHttpsRedirection();
app.UseRouting();
app.UseCors();
app.UseAuthentication();
app.UseAuthorization();
app.MapControllers();

If set up like that "[EnableCors("Open")]" on the controller should work.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM