我想为 Blazor 中的身份验证错误指定非默认布局

I want to specify a non-default layout for authentication errors in Blazor

我想在下面的错误中指定布局。

文件详细信息

App.razor

<CascadingAuthenticationState>
    <Router AppAssembly="@typeof(App).Assembly">
        <Found Context="routeData">
            <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
                <NotAuthorized>
                    <!-- TODO RZ9999 when Context removed -->
                    <AuthorizeView Context="authenticated">
                        <Authorized>
                            <!-- TODO ErrorLayout -->
                            <Error403/>
                        </Authorized>
                        <NotAuthorized>
                            <!-- TODO ErrorLayout -->
                            <Error401/>
                        </NotAuthorized>
                    </AuthorizeView>
                </NotAuthorized>
            </AuthorizeRouteView>
            <FocusOnNavigate RouteData="@routeData" Selector="h1"/>
        </Found>
        <NotFound>
            <LayoutView Layout="@typeof(ErrorLayout)">
                <Error404/>
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>

Error401.razor、Error403.razor、Error404.razor

<PageTitle>Error401</PageTitle>

<h3>Error401</h3>
<PageTitle>Error403</PageTitle>

<h3>Error403</h3>
<PageTitle>Error404</PageTitle>

<h3>Error404</h3>

我试过的

根据File details中的描述,Error404用的是ErrorLayout,Error401和Error403用的是MainLayout
我尝试了以下描述,但没有用。

添加@layout

Error401.razor 如下,但应用了 MainLayoute。 @layout 只对@page 有效吗?

@layout ErrorLayout

<PageTitle>Error401</PageTitle>

<h3>Error401</h3>

添加布局视图

如果 Error401 和 Error403 是 LayoutView 的子级,它们将嵌套在 MainLayout 和 ErrorLayout 布局中。

<AuthorizeView Context="authenticated">
    <Authorized>
        <LayoutView Layout="@typeof(ErrorLayout)">
            <Error403/>
        </LayoutView>
    </Authorized>
    <NotAuthorized>
        <LayoutView Layout="@typeof(ErrorLayout)">
            <Error401/>
        </LayoutView>
    </NotAuthorized>
</AuthorizeView>

问题

如果授权和认证错误,如何编写一个 Router 来指定布局?

Is @layout only valid for those with @page?

是的……您也可以将其添加到布局中以指定嵌套。

仅供参考:401 和 403 都被 <NotAuthorized> 捕获。

使用如下组件:

public class RedirectToPage : ComponentBase
{
    [Inject]
    private NavigationManager Navigation { get; set; }

    [Parameter]
    public string Href { get; set; }

    protected override void OnInitialized()
        => Navigation.NavigateTo(Href);
}

您可以将其扩展为包含 return 地址等。

在你的App.razor

里面
<NotAuthorized>
@if (context.User.Identity?.IsAuthenticated == true)
{
    <RedirectToPage Href="/error403" />
}
else
{
    <RedirectToPage Href="/error401" />
}
</NotAuthorized>

使用您选择的 @layout ... 创建适当的错误页面。

我通过创建自定义版本的 AuthorizeRouteView 解决了这个问题。
基于 Blazor 源 AuthorizeRouteView 创建具有以下更改的 CustomAuthorizeRouteView。

public sealed class CustomAuthorizeRouteView : RouteView
{
...
    [Parameter]
    public Type NotAuthorizedLayout { get; set; }
...
    private void RenderContentInNotAuthorizedLayout(RenderTreeBuilder builder, RenderFragment content)
    {
        builder.OpenComponent<LayoutView>(0);
        builder.AddAttribute(1, nameof(LayoutView.Layout), NotAuthorizedLayout);
        builder.AddAttribute(2, nameof(LayoutView.ChildContent), content);
        builder.CloseComponent();
    }

    private void RenderNotAuthorizedInDefaultLayout(RenderTreeBuilder builder, AuthenticationState authenticationState)
    {
        var content = NotAuthorized ?? _defaultNotAuthorizedContent;
        RenderContentInNotAuthorizedLayout(builder, content(authenticationState));
    }
...
}

App.razor

<CascadingAuthenticationState>
    <Router AppAssembly="@typeof(App).Assembly">
        <Found Context="routeData">
            <CustomAuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" NotAuthorizedLayout="@typeof(ErrorLayout)">
                <NotAuthorized>
                    @if (context.User.Identity?.IsAuthenticated != true)
                    {
                        <Error401/>
                    }
                    else
                    {
                        <Error403/>
                    }
                </NotAuthorized>
            </CustomAuthorizeRouteView>
            <FocusOnNavigate RouteData="@routeData" Selector="h1"/>
        </Found>
        <NotFound>
            <LayoutView Layout="@typeof(ErrorLayout)">
                <Error404/>
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>

有了这个内容,我可以在没有导航的情况下用原来的 URL 做我想做的事。

完整来源