如何获取用户是否登录的最新信息?

gre*_*man 4 authentication blazor blazor-webassembly

在这种特殊情况下,我只对获取用户是否登录的信息感兴趣。

按照答案如何根据用户是否登录来启用/禁用元素?我可以获取此信息,但有一个奇怪的问题。

我使用 Blazor 演示应用程序,它在顶部显示提供的“LoginDisplay.razor”组件,我自己的页面使用以下代码:

@code {
  protected override async Task OnInitializedAsync()
  {
      Console.WriteLine("Init");

      var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
      var authenticated = authState.User.Identity?.IsAuthenticated ?? false;

      Console.WriteLine($"We are {authenticated}");
  }
}
Run Code Online (Sandbox Code Playgroud)

我使用这个应用程序时分为三个步骤:

  1. 我启动应用程序,我没有登录,“LoginDisplay”显示“登录”提示,我的代码打印我没有经过身份验证 - 很好

  2. 我点击“登录”,登录,我被重定向回我的页面 - “LoginDisplay”现在显示我的名字,但我的代码仍然打印我没有经过身份验证(使用“NavMenu.razor”时会发生这种不正确的打印输出)但使用“Index.razor”时没问题——请参阅下面的更新)

  3. 我按 F5(重新加载页面)——“LoginDisplay”显示我的名字,代码打印出我已通过身份验证——正如预期的那样

所以步骤(2)是有问题的——我应该获取我登录的信息(因为我就是),显然“LoginDisplay”能够实现这个事实。那么我应该在代码中添加什么逻辑才能显示我已登录?

更新@enet 回复后,我意识到步骤 (2) 的结果取决于您放置此代码的位置 - 如果在登录打印输出后立即将其放置在“NavMenu.razor”中,则表明您未获得授权。当我将相同的代码放入“Index.razor”(主页)时,打印输出正确地表明我已登录。

我可以看到渲染“NavMenu”几乎是立即的,而“Index”是在暂停一段时间后渲染的。所以问题更多是“无论使用页面如何获取新的身份验证信息?”。

Isa*_*aac 8

以下代码描述了如何在 MainLayout 组件中显示消息:

<LoginDisplay />
<div>IsAuthenticated: @authenticated.ToString()</div>


@code {

bool authenticated;

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

protected override async Task OnInitializedAsync()
{
    Console.WriteLine("Init");

    var authState = await authenticationStateTask;
    var user = authState.User;


    authenticated = user.Identity?.IsAuthenticated ?? false;
    Console.WriteLine($"We are {authenticated}");
}
Run Code Online (Sandbox Code Playgroud)

}

注意,上面的代码仅在MainLayout组件初始化时执行。为了刷新已验证消息的显示,我们需要再次执行代码。这可以通过执行以下操作来实现:

在 Authentication 组件中,将OnLogInSucceeded用户登录后调用的事件处理程序属性添加到 RemoteAuthenticatorView 组件实例,如下所示:

<RemoteAuthenticatorView Action="@Action" OnLogInSucceeded="RefreshMain" />
Run Code Online (Sandbox Code Playgroud)

添加事件处理程序RefreshMain

 private void RefreshMain()
    {
        NavigationManager.NavigateTo("mainlayout");
    }
Run Code Online (Sandbox Code Playgroud)

事件处理程序代码只需重定向到 MainLayout

为 NavigationManager 添加 @inject 指令,如下所示:

@inject NavigationManager NavigationManager;
Run Code Online (Sandbox Code Playgroud)

请注意,您可以简单地使用 AuthorizeView 组件,如下所示:

<LoginDisplay />

<div>
<AuthorizeView>
    <Authorized>
        <div>@context.User.Identity.IsAuthenticated</div>
    </Authorized>
    <NotAuthorized>
        <div>@context.User.Identity.IsAuthenticated</div>
    </NotAuthorized>
</AuthorizeView>
</div>
Run Code Online (Sandbox Code Playgroud)

更新

您通常不直接使用 AuthenticationStateProvider。使用本文后面描述的 AuthorizeView 组件或任务方法。直接使用 AuthenticationStateProvider 的主要缺点是,如果底层身份验证状态数据发生更改,则不会自动通知组件。 来源...

不要为渲染操心太多。通常,除非您的代码无休止地重新渲染,否则不会有任何问题。

无论如何,以下代码示例描述了您应该如何真正做到这一点:

将 Authentication 组件中的代码反转为其默认状态

将您在 MainLayout 中添加的代码更改为以下内容

 @inherits LayoutComponentBase

 @inject AuthenticationStateProvider AuthenticationStateProvider

 <div class="page">
    <div class="sidebar">
        <NavMenu />
    </div>

    <div class="main">
        <div class="top-row px-4 auth">
            <LoginDisplay />
            <div>IsAuthenticated: @authenticated.ToString()</div>
            <a href="https://learn.microsoft.com/aspnet/" 
                                        target="_blank">About</a>
        </div>
        <div class="content px-4">
            @Body
        </div>
     </div>
  </div>

  @code {

    private bool authenticated;

    protected override void OnInitialized()
    {
        Task<AuthenticationState> _currentAuthenticationStateTask;

        AuthenticationStateProvider.AuthenticationStateChanged += 
                                       OnAuthenticationStateChanged;

        _currentAuthenticationStateTask = 
          AuthenticationStateProvider.GetAuthenticationStateAsync();

        OnAuthenticationStateChanged(_currentAuthenticationStateTask);
    }

    private void OnAuthenticationStateChanged
                  (Task<AuthenticationState> authenticationStateTask)
    {
        _ = InvokeAsync(async () =>
        {
            var authState = await authenticationStateTask;
            var user = authState.User;


            authenticated = user.Identity?.IsAuthenticated ?? false;
            StateHasChanged();
        });
    }

  }
Run Code Online (Sandbox Code Playgroud)