Search code examples
blazor-client-side

How to get the notification that a user has been successfully logged in?


When user is logged in, I'd like to fetch user's profile data so that I can display them throughout the application.

<CascadingValue Value="@UserProfile">
   <div class="content px-4">
     @Body
   </div>
</CascadingValue>

I'd like to be able to intercept a request so that I can check 1) the user is logged in and 2) the UserProfile object is set. If the user's logged in but the object is not set then I'll make a request to the API to get data.

Here's the portion of the App.razor code.

<Found Context="routeData">
        <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
            <NotAuthorized>
                @if (!context.User.Identity.IsAuthenticated)
                {
                    <RedirectToLogin />
                }
                else
                {
                    <p>You are not authorized to access this resource.</p>
                }
            </NotAuthorized>
            <Authorizing>
            </Authorizing>
        </AuthorizeRouteView>
    </Found>

<Authorizing></Authorizing> can be used for when the authentication process is going on. How do I know when the process is done and that the user's logged in, so that I can fetch user's profile.

Thanks for helping.


Solution

  • The answer is the RemoteAuthenticatorView component on the Authenticator.razor page. This component exposes all sort of properties that covers so many scenarios, i.e. OnLogInSucceeded, OnLogOutSucceeded, OnLogOutFailed, and so forth.

    In my case, I wanted to queries user's profile data as soon as the login succeeds so I can display which organization's he/she belongs to.

    @page "/authentication/{action}"
    @using Microsoft.AspNetCore.Components.WebAssembly.Authentication
    
    <RemoteAuthenticatorView 
      AuthenticationState="RemoteAuthenticationState"
      OnLogInSucceeded="@RestoreAppState" //this is the event I was looking for
      Action="@Action" />
    

    OnLoggInSucceeded is what I was looking for

    public partial class Authentication
    {
        [Inject] AppState AppState { get; set; }
        [Inject] HttpClient Http { get; set; }
    
        [Parameter] public string Action { get; set; }
    
        public AppAuthenticationState RemoteAuthenticationState { get; set; } =
            new AppAuthenticationState();
    
        protected override void OnInitialized()
        {
            if (RemoteAuthenticationActions.IsAction(RemoteAuthenticationActions.LogIn, Action))
            {
                // Preserve the current order so that we don't loose it
                //RemoteAuthenticationState.Order = OrderState.Order;
            }
        }
    
        private async Task RestoreAppState()
        {
            if (string.IsNullOrEmpty(AppState.RootInstitutionName))
            {
                try
                {
                    var profileData = await Http.GetFromJsonAsync<UserProfileData>("userprofiles");
                    AppState.RootInstitutionName = profileData.RootInstitution.InstitutionName;
                }
                catch (AccessTokenNotAvailableException exception)
                {
                    exception.Redirect();
                }
            }
        }
    }
    

    There's even a possibility to preserve data between operations, such login, logout. It was good to watch Daniel Roth explaining security works in Blazor.