Blazor WebAssembly 授权

Posted

技术标签:

【中文标题】Blazor WebAssembly 授权【英文标题】:Blazor WebAssembly Authorize 【发布时间】:2021-02-08 20:47:20 【问题描述】:

我从一个 Visual Studio 模板开始,这是一个新的 Blazor WebAssembly,具有身份验证和 Web 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 被阻止,因为 [Authorize]。

但是现在问题来了。 使用 var response = await Http.GetAsync("Api/WeatherForecast/Get");我得到一个 HttpCode 200 回来。但是 API 从来没有被调用过?!它来自哪里?

这里有什么问题吗?如何确保我的主页和我的 API 安全?

我不想像这样在每个页面中都使用 AuthenticationStateProvider:

@代码

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,然后在OnInitializedAsync() 中使用GetAuthenticationStateAsync(); 获取身份验证状态。示例:

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");
    

您可以不使用&lt;AuthorizeView /&gt; 组件来处理为经过身份验证/授权的用户呈现内容。我自己的应用程序示例:

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

如果当前用户登录,我只使用它来呈现我的导航。如果没有,则没有菜单。

【讨论】:

以上是关于Blazor WebAssembly 授权的主要内容,如果未能解决你的问题,请参考以下文章

Blazor WebAssembly身份认证与授权

Blazor WebAssembly身份认证与授权

Blazor WebAssembly+Duende.IdentityServer+EF Core认证授权企业级实战

当用户在 Blazor Webassembly 身份验证和授权中具有多个角色时出现问题?

Blazor WebAssembly .Net 5 Msal 身份验证中基于角色的授权

Blazor WebAssembly+Duende.IdentityServer+EF Core认证授权企业级实战