Авторизация веб-сборки Blazor

#asp.net-core #blazor-client-side #blazor-webassembly

#asp.net-ядро #blazor-на стороне клиента #blazor-веб-сборка

Вопрос:

Я начал с шаблона Visual Studio, новой веб-сборки Blazor с аутентификацией и веб-API на стороне сервера.

Теперь я хочу защитить свои страницы и API сервера. Я делаю следующее:

 Page:
<AuthorizeView Roles="Administrator">
    <Authorized>
        <h1>Weather forecast</h1>

        <p>This component demonstrates fetching data from the server.</p>

        @if (forecasts == null)
        {
            <p><em>Loading...</em></p>
        }
        else
        {
            <table class="table">
                <thead>
                    <tr>
                        <th>Date</th>
                        <th>Temp. (C)</th>
                        <th>Temp. (F)</th>
                        <th>Summary</th>
                    </tr>
                </thead>
                <tbody>
                    @foreach (var forecast in forecasts)
                    {
                        <tr>
                            <td>@forecast.Date.ToShortDateString()</td>
                            <td>@forecast.TemperatureC</td>
                            <td>@forecast.TemperatureF</td>
                            <td>@forecast.Summary</td>
                        </tr>
                    }
                </tbody>
            </table>
        }
    </Authorized>
    <NotAuthorized>
    ...
    </NotAuthorized>
</AuthorizeView>

@code {

    private WeatherForecast[] forecasts;

    protected override async Task OnInitializedAsync()
    {
        var response = await Http.GetAsync("Api/WeatherForecast/Get");
        //var resp = await Http.GetFromJsonAsync<WeatherForecast[]>("Api/WeatherForecast/Get");

        if (response.IsSuccessStatusCode)
        {
            var s = await response.Content.ReadAsStringAsync();
            forecasts = await response.Content.ReadFromJsonAsync<WeatherForecast[]>();
        }
    }
}

API
[Authorize]
    [ApiController]
    [Route("api/[controller]/[action]")]
    public class WeatherForecastController : Controller
    {
        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)
        {
            this.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();
        }
    }
  

Пользователь, вызывающий страницу «fetchdata», не вошел в систему и не может отобразить сайт des.
Но OnInitializedAsync все еще вызывается. API блокируется, потому что [Авторизовать].

Но теперь возникает проблема. С помощью ответа var = await Http.GetAsync(«Api / WeatherForecast / Get»); я получаю обратно HttpCode 200. Но API никогда не вызывается ?! Откуда это взялось?

Что-то здесь не так? Как я могу сделать мою страницу и мой API безопасными?

Я не хочу использовать AuthenticationStateProvider на каждой странице подобным образом:

@code {

 private WeatherForecast[] forecasts;

[CascadingParameter]
Task<AuthenticationState> authenticationStateTask { get; set; }

protected override async Task OnInitializedAsync()
{

    if(authenticationStateTask.Result.User.IsInRole("Administrator"))
    {
        var response = await Http.GetAsync("Api/WeatherForecast/Get");
        //var resp = await Http.GetFromJsonAsync<WeatherForecast[]>("Api/WeatherForecast/Get");

        if (response.IsSuccessStatusCode)
        {
            var s = await response.Content.ReadAsStringAsync();
            forecasts = await response.Content.ReadFromJsonAsync<WeatherForecast[]>();
        }
    }

}
  

}

Ответ №1:

Вам не нужно! 🙂 Вопрос в том, хотите ли вы, чтобы все приложение было безопасным или только пара страниц?

Лично я предпочитаю вводить @inject AuthenticationStateProvider AuthenticationStateProvider , а затем получать состояние аутентификации, используя GetAuthenticationStateAsync(); inside of OnInitializedAsync() . Пример:

 protected override async Task OnInitializedAsync()
{
    try
    {
        var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
        if(authState.User.Identity.IsAuthenticated)
            UserName = $"Hi, {authState.User.Claims.FirstOrDefault(x => x.Type == "display_name")?.Value}!";
    }
    catch (Exception ex)
    {
        Logger.LogError($"Failed to initialize menu. Error: {ex}");
    }
}
  

Вам может сойти с рук использование <AuthorizeView /> компонентов для обработки содержимого рендеринга для аутентифицированных / авторизованных пользователей. Пример из моего собственного приложения:

 <AuthorizeView>
    <Authorized>
        <CascadingValue Name="DeviceType" IsFixed="true" Value="DeviceType">
            <NavMenu />
        </CascadingValue>
    </Authorized>
</AuthorizeView>
  

Я использую это для отображения моей навигации только в том случае, если текущий пользователь вошел в систему. Если нет, меню отсутствует.