How to get fresh information whether the user is logged in?

末鹿安然 提交于 2021-02-11 16:57:54

问题


In this particular case I am only interested in getting info whether the user is logged in or not.

Following the answers How to enable/disable elements depending whether the user is logged in or not? I can fetch this information but there is one odd problem.

I use Blazor demo app which displays provided "LoginDisplay.razor" component at top, my own page uses following code:

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

I have three steps when using this app:

  1. I start the app, I am not logged in, "LoginDisplay" shows "log in" prompt and my code prints I am not authenticated -- good

  2. I click on "log in", I log in, I am redirected back to my page -- "LoginDisplay" now shows my name, yet my code still prints I am not authenticated (this incorrect printout happens when using "NavMenu.razor" but it is fine when when using "Index.razor" -- see update below)

  3. I hit F5 (reload the page) -- "LoginDisplay" shows my name, and the code prints I am authenticated -- as expected

So step (2) is problematic -- I should get the info I am logged in (because I am), and obviously "LoginDisplay" is capable of realizing this fact. So what logic should I add to my code that it too would show I am logged in?

Update After @enet reply I realized the outcome of the step (2) depends where you put this code -- if it placed in "NavMenu.razor" right after logging in the printout states you are not authorized. When I put the same code in "Index.razor" (home page) the printout correctly states I am logged in.

I can see that rendering "NavMenu" is almost immediate, while "Index" is rendered after some pause. So the problem is more "how to get fresh authentication info regardless the page is used?".


回答1:


The following code describes how you can display your message in the MainLayout component:

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

}

Note that the above code is executed only when the MainLayout component is initialized. In order to refresh the display of the authenticated message, we need to executed the code once more. This may be achieved by doing the following:

In the Authentication component add to the RemoteAuthenticatorView component instance the event handler attribute OnLogInSucceeded that is called after the user has logged in, like this:

<RemoteAuthenticatorView Action="@Action" OnLogInSucceeded="RefreshMain" />

Add the event handler RefreshMain

 private void RefreshMain()
    {
        NavigationManager.NavigateTo("mainlayout");
    }

The event handler code simply redirect to the MainLayout

Add @inject directive for the NavigationManager, like this:

@inject NavigationManager NavigationManager;

Note that instead of the code above you can simply use the AuthorizeView component like this:

<LoginDisplay />

<div>
<AuthorizeView>
    <Authorized>
        <div>@context.User.Identity.IsAuthenticated</div>
    </Authorized>
    <NotAuthorized>
        <div>@context.User.Identity.IsAuthenticated</div>
    </NotAuthorized>
</AuthorizeView>
</div>

Update

You don't typically use AuthenticationStateProvider directly. Use the AuthorizeView component or Task approaches described later in this article. The main drawback to using AuthenticationStateProvider directly is that the component isn't notified automatically if the underlying authentication state data changes. Source...

Don't bother yourself too much about rendering. Ordinarily, there is no issue unless your code re-render endlessly.

Anyhow, the following code sample describes how you should really do that:

Reverse the code in the Authentication component to its default state

Change the code you added in the MainLayout to the following

 @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://docs.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();
        });
    }

  }


来源:https://stackoverflow.com/questions/65805802/how-to-get-fresh-information-whether-the-user-is-logged-in

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!