4
votes

Comment informer correctement l'interface utilisateur de Blazor que mon état d'utilisateur a changé?

J'apprends actuellement le core et le blazor asp.net, et j'ai rencontré un problème avec peu de documentation. J'ai une application Blazor côté serveur et je m'authentifie pour utiliser le stockage local et le ServerAuthenticationStateProvider. Ce code est basé sur ce guide , voici mon implémentation actuelle du fournisseur d'état:

MyAuthenticationStateProvider.cs

@page "/loginControl"
@inject IAuthService AuthService
@inject NavigationManager NavigationManager

    <AuthorizeView>

        <Authorized>

            <b>Hello, @context.User.Identity.Name!</b>

            <a class="ml-md-auto btn btn-primary"
               href="logout?returnUrl=/"
               target="_top">Logout</a>

        </Authorized>

        <Authorizing>
            <b>Authentication in progress</b>
        </Authorizing>

        <NotAuthorized>

            <input type="text"
                   placeholder="Email"
                   @bind="@email" />

            &nbsp;&nbsp;

            <input type="password"
                   placeholder="Password"
                   @bind="@password" />

            <button class="ml-md-auto btn btn-primary"
                    @onclick="@createSession">
                Login
            </button>

        </NotAuthorized>

    </AuthorizeView>

@code {

    string email = "";

    string password = "";

    async void createSession()
    {

        var loginRequest = new LoginRequest
        {

            Email = email,
            Password = password

        };

        await AuthService.Login(loginRequest);
    }

}

LoginControl.cs

namespace BlazorApp
{
    public class MyAuthenticationStateProvider : ServerAuthenticationStateProvider
    {
        private readonly HttpClient _httpClient;
        private readonly ILocalStorageService _localStorage;

        public MyAuthenticationStateProvider(HttpClient httpClient, ILocalStorageService localStorage)
        {
            _httpClient = httpClient;
            _localStorage = localStorage;
        }
        public override async Task<AuthenticationState> GetAuthenticationStateAsync()
        {
            var savedToken = await _localStorage.GetItemAsync<string>("authToken");

            if (string.IsNullOrWhiteSpace(savedToken))
            {
                return new AuthenticationState(new ClaimsPrincipal(new ClaimsIdentity()));
            }

            var user = new ClaimsPrincipal(new ClaimsIdentity(ParseClaimsFromJwt(savedToken), "jwt"));

            return new AuthenticationState(user);
        }

        public void MarkUserAsAuthenticated(string token)
        {
            var authenticatedUser = new ClaimsPrincipal(new ClaimsIdentity(ParseClaimsFromJwt(token), "jwt"));
            var authState = Task.FromResult(new AuthenticationState(authenticatedUser));
            NotifyAuthenticationStateChanged(authState);

        }

Je m'attendrais à ce qu'après l' NotifyAuthenticationStateChanged(AuthState) , mon interface utilisateur de connexion NotifyAuthenticationStateChanged(AuthState) et le contenu <Authorized> s'affiche. Cependant, mon interface utilisateur affiche toujours le contenu <NotAuthorized> . Ai-je manqué quelque chose à voir avec l'envoi au thread principal? Je suis très nouveau dans tout cela, mais mon mentor a mentionné quelque chose à voir avec cela peut-être être un fil d'arrière-plan ne disant pas à l'interface utilisateur de refaire le rendu.


0 commentaires

3 Réponses :


3
votes

Vraiment simple. Tout ce que vous avez à faire est:

// Get the loginResponse
LoginResponse loginResponse = await PlayerService.Login(emailAddress, password);

// if the loginResponse exists
if (NullHelper.Exists(loginResponse))
{
   // set the player
   player = loginResponse.Player;

   // Perform the Login
  await OnLogin.InvokeAsync(loginResponse);
}

Je viens de créer un contrôle de connexion hier, alors voici quelques bonus que vous voudrez peut-être savoir:

Mon contrôle de connexion a ceci:

<Login OnLogin="LoginComplete"></Login>

/// <summary>
/// This method returns the LoginResponse object 
/// </summary>
/// <param name="loginResponse"></param>
private void LoginComplete(LoginResponse loginResponse)
{
    // if the login was successful
    if (loginResponse.Success)
    {
        // Set the player
        player = loginResponse.Player;

        // refresh the UI
        this.StateHasChanged();
    }
}

Et dans votre contrôle pour appeler le délégué LoginResponse

StateHasChanged();


4 commentaires

Que contient votre réponse de connexion? Je ne suis pas tout à fait sûr de ce que fait la ligne d' await OnLogin.InvokeAsync(loginresponse)


Voici le code de LoginResponse, bien que ce projet ne soit pas encore prêt à être cloné. github.com/DataJuggler/CardCounter/blob/master/Data/… Ceci est juste une classe que j'ai écrite Spécifique à BlackJack, donc après avoir connecté le joueur depuis le contrôle de connexion, je peux renvoyer une réponse avec un joueur et son solde de jetons , équilibre du marché, etc. ou une réponse échouée avec un message. Le contrôle de connexion dans le dossier des composants et la page d'index est l'endroit où se trouve tout le code qui fonctionne.


Pour répondre à votre question, voici le code du contrôle de connexion: github.com/DataJuggler/CardCounter/blob/master/Components / ... À la ligne 69 (au moment de la rédaction de cet article), la méthode HandleLogin appelle le service Player pour effectuer le login et pour renvoyer la réponse à la page d'index, vous définissez le paramètre OnLoginComplete à la ligne 279: [Parameter] public EventCallback <LoginResponse> OnLogin {get; ensemble; } Ensuite, la page Index reçoit la réponse.


Après être passé à Blazor côté client, je suis tombé sur un problème similaire et je me suis souvenu de cette réponse qui a aidé. Il semble que je puisse également utiliser les fonctions de tâche et l'interface utilisateur attendra la tâche, puis se mettra à jour en conséquence



1
votes

Je me suis trompé, le blazor côté serveur implémente déjà AuthenticationStateProvider , donc tout ce que j'ai à faire est d'implémenter quelque chose qui définit user.identity.isauthenticated , j'utilise des cookies et un jeton pour ce faire.


1 commentaires

Ce sont les types de réponses qui fournissent un indice, mais qui sont trop vagues pour faire avancer quoi que ce soit. Citer all I need to do is to implement something that sets the user.identity.isauthenticated Comment faire exactement cela?



0
votes

J'ai résolu le problème en redirigeant l'utilisateur avec le gestionnaire de navigation et en forçant la redirection (en faisant cela, l'application est obligée de changer le authState). Je n'ai fait cela que parce que StateChanged() ne fonctionnait pas.

NaviMngr.NavigateTo("/", true);


0 commentaires