Search code examples
c#asp.net-coreblazorwebassembly

Blazor WebAssembly blocks WebApi AllowAnonymous


I have created an Blazor WebAssembly project and want to provide a WebAPI with one public available function.

[Route("api/[controller]")]
[ApiController]
[Authorize]
public class SystemEvalApiController : ControllerBase
{
    public SystemEvalApiController(AppDbContext context, IMapper mapper)
    {...}

    [Route("LatestEvals")]
    [AllowAnonymous]
    public ActionResult LatestEvals()

that is my Api controller and I should be able to call it with:

SystemEvalPublicViewModel = await Http
                .GetFromJsonAsync<SystemEvalPublicViewModel>(
                    HttpService.BuildUrl("api/SystemEvalApi/LatestEvals"));

When i am not logged into any account. But instead I get this error:

info: System.Net.Http.HttpClient.JPB.BorannRemapping.ServerAPI.LogicalHandler[100]
      Start processing HTTP request GET https://localhost:44330/api/SystemEvalApi/LatestEvals
blazor.webassembly.js:1 info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[2]
      Authorization failed.

It looks like the "DefaultAuthorizationService" does not recognize the Anonymous attribute but I cannot find the point where it fails directly.

How do I declare an WebAPI function to be accessable from the HttpClient without Login. Microsoft.AspNetCore.Components.WebAssembly.Server 3.2.0.-rc1.20223.4

Edit: Here is the declaration for ClientServices:

var builder = WebAssemblyHostBuilder.CreateDefault(args);
builder.RootComponents.Add<App>("app");

builder.Services.AddHttpClient("JPB.BorannRemapping.ServerAPI", client =>
    {
        client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress);
    })
    .AddHttpMessageHandler<BaseAddressAuthorizationMessageHandler>();

// Supply HttpClient instances that include access tokens when making requests to the server project
builder.Services.AddTransient(sp => sp.GetRequiredService<IHttpClientFactory>().CreateClient("JPB.BorannRemapping.ServerAPI"));
builder.Services.AddTransient(e => new HttpService(e.GetService<HttpClient>()));
builder.Services.AddApiAuthorization();
builder.Services.AddBlazoredLocalStorage();

await builder.Build().RunAsync();

Solution

  • So each time you acquire an HttpClient it use the BaseAddressAuthorizationMessageHandler which try to authentify the request. But it this case your request should not be authentified, so you can make something like :

    Registration

    builder.Services.AddHttpClient("JPB.BorannRemapping.ServerAPI.Anonymous", client =>
        {
            client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress);
        });
    

    Usage

    @inject IHttpClientFactory _factory
    
    @code {
    ...
         var httpClient = _factory.CreateClient("JPB.BorannRemapping.ServerAPI.Anonymous");
         var httpService = new HttpService(httpClient);
         SystemEvalPublicViewModel = await httpClient
                    .GetFromJsonAsync<SystemEvalPublicViewModel>(
                        httpService.BuildUrl("api/SystemEvalApi/LatestEvals"));
    }