简体   繁体   中英

Make anonymous call to Server in ASP.NET Core hosted Blazor App

I created a Blazor Webassembly app from the included template in VS with Authorization and ASP.NET Core hosted options as shown here:

创建 Blazor 对话框

I want to be able to make http requests to the server without being authenticated. I changed the code in the WeatherForecastController by commenting out the [Authorize] attribute (and even added an [AllowAnonymous] attribute):

//[Authorize] CHANGED
[AllowAnonymous] //CHANGED
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
    private static readonly string[] Summaries = new[]
    {
        "Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"
    };

    private readonly ILogger<WeatherForecastController> _logger;

    public WeatherForecastController(ILogger<WeatherForecastController> logger)
    {
        _logger = logger;
    }

    [HttpGet]
    public IEnumerable<WeatherForecast> Get()
    {
        var rng = new Random();
        return Enumerable.Range(1, 5).Select(index => new WeatherForecast
        {
            Date = DateTime.Now.AddDays(index),
            TemperatureC = rng.Next(-20, 55),
            Summary = Summaries[rng.Next(Summaries.Length)]
        })
        .ToArray();
    }
}

In the FetchData.razor page, along with other changes noted in the code, I commented out @attribute [Authorize] :

@page "/fetchdata"
@using Microsoft.AspNetCore.Authorization
@using Microsoft.AspNetCore.Components.WebAssembly.Authentication
@using StackOverflowAuthProblem.Shared
@*@attribute [Authorize]*@ @*CHANGED*@
@inject HttpClient Http

@*CHANGED Html removed for brevity*@

<div>Exception message: @exceptionMessage</div>

@code {
    private WeatherForecast[] forecasts;

    string exceptionMessage; //CHANGED

    protected override async Task OnInitializedAsync()
    {
        try
        {
            forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
        }
        catch (AccessTokenNotAvailableException exception)
        {
            exceptionMessage = exception.Message; //CHANGED returns an empty string

            exceptionMessage = exception.ToString(); //CHANGED returns
                //Microsoft.AspNetCore.Components.WebAssembly.Authentication.AccessTokenNotAvailableException: '' at
                //Microsoft.AspNetCore.Components.WebAssembly.Authentication.AuthorizationMessageHandler.SendAsync(HttpRequestMessage request,
                //CancellationToken cancellationToken) at Microsoft.Extensions.Http.Logging.LoggingScopeHttpMessageHandler.SendAsync(
                //    HttpRequestMessage request, CancellationToken cancellationToken)
                //at System.Net.Http.HttpClient.SendAsyncCore(HttpRequestMessage request,
                //HttpCompletionOption completionOption, Boolean async, Boolean emitTelemetryStartStop,
                //CancellationToken cancellationToken) 
                //at System.Net.Http.Json.HttpClientJsonExtensions.<GetFromJsonAsyncCore>d__9`1[[StackOverflowAuthProblem.Shared.WeatherForecast[],
                //StackOverflowAuthProblem.Shared, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].MoveNext()
                //at StackOverflowAuthProblem.Client.Pages.FetchData.OnInitializedAsync()
                //in E:\StackOverflow\StackOverflowAuthProblem\StackOverflowAuthProblem\Client\Pages\FetchData.razor:line 53

            //exception.Redirect(); CHANGE
        }
    }
}

The exception I get is in the code above. I suspect the problem is in the App.razor page, but can't figure it out.

Any help?

Someone posted then deleted an answer here which said the problem was in following line in the Program.cs file of the client project:

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

Surely there's something I'm missing, otherwise can't help but think this is a major oversight that one can't hit an API endpoint without being authenticated.

public static class HttpClientService
{
    public static HttpClient AnonymousHttpClient { get; set; }

    static HttpClientService()
    {
        AnonymousHttpClient = new HttpClient();

#if DEBUG
        AnonymousHttpClient.BaseAddress = new Uri("https://localhost:44395/");
#else
        throw new Exception("Need the Base address here");
#endif

    }
}

My reasoning for putting it in it's own class library is that I plan on adding Razor Class Libraries and I want a single instance of the HttpClient to use across the solution because of the problem with sockets

Source: https://chrissainty.com/avoiding-accesstokennotavailableexception-when-using-blazor-webassembly-hosted-template-with-individual-user-accounts/

Reason: The default configuration in the template uses an HTTP client with a custom message handler called BaseAddressAuthorizationMessageHandler. This handler attempts to attach an access token to any outgoing requests and if it can't find one, it throws an exception.

Solution:

First create a class

public class PublicClient
{
    public HttpClient Client { get; }

    public PublicClient(HttpClient httpClient)
    {
        Client = httpClient;
    }
}

Register the class with Dependency Injection in the start up

builder.Services.AddHttpClient<PublicClient>(client => client.BaseAddress = new Uri(builder.HostEnvironment.BaseAddress));

Use it in razor pages

@inject PublicClient PublicClient

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