我正在实现一个自定义的 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
...
}
}
这个方法。
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>());
希望能帮到你...