BlazorNotifyAuthenticationStateChanged不会更新基于授权的元素。

问题描述 投票:0回答:1

我正在实现一个自定义的 AuthenticationStateProvider 并在mainLayout中使用用户申诉的信息。据我了解,在执行了 NotifyAuthenticationStateChanged 方法本身应该重新渲染所有使用了 <AuthorizeView> e.t.c.但它没有。此外,我为mainLayout实现了自己的重载器,并且我使用了 StateHasChanged 用户登录后。但由于某些原因,它仍然认为没有人授权,并将代码块以 <NotAuthorized> 块。但如果我手动重新加载页面 GetAuthenticationStateAsync 方法被执行,之后,在 <Authorized> 是呈现的。我是做错了什么,还是一个bug?我的 CustomAuthenticationStateProvider 的代码。

public class CustomAuthenticationStateProvider :  AuthenticationStateProvider
{
    private readonly ISessionStorageService _sessionStorage;
    public CustomAuthenticationStateProvider(ISessionStorageService sessionStorage)
    {
        _sessionStorage = sessionStorage;
    }

    public override async Task<AuthenticationState> GetAuthenticationStateAsync()
    {
        var userModel = await _sessionStorage.GetItemAsync<AuthorizedModel>("userModel");

        var identity = new ClaimsIdentity();
        if (userModel != null)
        {
            identity = new ClaimsIdentity( new []
            {
                //Some my claims
                ...
            }, "api");
        }
        else
        {
            identity = new ClaimsIdentity(); 
        }

        var claimsPrincipal = new ClaimsPrincipal(identity);

        return new AuthenticationState(claimsPrincipal);
    }

    public void AuthenticateUser(AuthorizedModel model)
    {
        var identity = new ClaimsIdentity(new []
        {
            //Some my claims
            ...
        });

        var user = new ClaimsPrincipal(identity);

        NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));
    }

    public async Task LogUserOut()
    {
        await _sessionStorage.RemoveItemAsync("nickName");

        var identity = new ClaimsIdentity();

        var user = new ClaimsPrincipal(identity);

        NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(user)));
    }
}

我的登录:

public async Task HandleValidSubmit()
{
    var authorizedUser = await loginRepository.TryLogin(_model);
    ...
    ((CustomAuthenticationStateProvider)authenticationStateProvider).AuthenticateUser(authorizedUser);
    await sessionStorage.SetItemAsync("userModel", authorizedUser);
    navigationManager.NavigateTo("/");
    //This is for my custom page reload 
    authorizationState.LoggedIn = true;
}

我的MainLayout:

@inherits LayoutComponentBase
...
    <AuthorizeView>
        <Authorized>
            <UserInfo />
        </Authorized>
        <NotAuthorized>
            //Some block of code for non-authorized
            ...
        </NotAuthorized>
    </AuthorizeView>
    ...

最后是UserInfo代码

@using System.Security.Claims
...
<div class="user-info">
    <span class="user-name">
        @userFirstName
        <strong>@userSecondName</strong>
    </span>
    <span class="user-role">@userNickName</span>
    <span class="user-status">
        <i class="fa fa-circle"></i>
        <span>Online</span>
    </span>
</div>

@code{
    [CascadingParameter]
    private Task<AuthenticationState> authenticationStateTask { get; set; }
    ClaimsPrincipal user;
    string userFirstName;
    ...

    protected override async Task OnInitializedAsync()
    {
        user = (await authenticationStateTask).User;
        //Here I just get userInfo from claims
        ...
    } 
}
c# authentication blazor
1个回答
2
投票

这个方法。

public void AuthenticateUser(AuthorizedModel model)
{
    var identity = new ClaimsIdentity(new []
    {
        //Some my claims
        ...
    });

    var user = new ClaimsPrincipal(identity);

    NotifyAuthenticationStateChanged(Task.FromResult(new 
   AuthenticationState(user)));
 }

应该是这样的

public void AuthenticateUser()
{
   // If AuthorizedModel model contains a Jwt token or whatever which you 
   // save in the 
   // local storage, then add it back as a parameter to the AuthenticateUser
   // and place here the logic to save it in the local storage
   // After which call NotifyAuthenticationStateChanged method like this.

   NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
}

注意:对StateHasChanged方法的调用与当前问题无关。调用基类的NotifyAuthenticationStateChanged是为了让基类,也就是AuthenticationStateProvider调用AuthenticationStateChanged事件,将AuthenticationState对象传递给订阅者,在这种情况下,传递给CascadingAuthenticationState组件,告诉他刷新它的数据(AuthenticationState)。

注意:如果在做了上述改动后问题仍然存在,请确保您在DI容器中添加以下内容。

  services.AddScoped<CustomAuthenticationStateProvider>();
        services.AddScoped<AuthenticationStateProvider>(provider => 
        provider.GetRequiredService<CustomAuthenticationStateProvider>());

希望能帮到你...

© www.soinside.com 2019 - 2024. All rights reserved.