问题
I use blazor with server side render and I want to do my own AuthenticationStateProvider, but it's not work and I do not know why.
My ovveride method in public class LocalAuthenticationStateProvider : AuthenticationStateProvider:
public async override Task<AuthenticationState> GetAuthenticationStateAsync()
{
if (await _storageService.ContainKeyAsync("User"))
{
var userInfo = await _storageService.GetItemAsync<LocalUserInfo>("User");
var claims = new[]
{
new Claim("Email", userInfo.Email),
new Claim("FirstName", userInfo.FirstName),
new Claim("LastName", userInfo.LastName),
new Claim("AccessToken", userInfo.AccessToken),
new Claim(ClaimTypes.NameIdentifier, userInfo.Id),
};
var identity = new ClaimsIdentity(claims, "BearerToken");
var user = new ClaimsPrincipal(identity);
var state = new AuthenticationState(user);
NotifyAuthenticationStateChanged(Task.FromResult(state));
return state;
}
return new AuthenticationState(new ClaimsPrincipal());
}
My Login Page:
@inject AuthenticationStateProvider authenticationStateProvider
await storageService.SetItemAsync("User", userInfo);
await authenticationStateProvider.GetAuthenticationStateAsync();
navigationManager.NavigateTo("/");
My Startup.cs
services.AddAuthentication();
services.AddAuthorization();
services.AddAuthorizationCore();
services.AddScoped<AuthenticationStateProvider, LocalAuthenticationStateProvider>();
My Index.razor for check auth. This always NotAuthorized
<AuthorizeView>
<Authorized>
<h1>Hi! @context.User.FindFirst("FirstName").Value</h1>
</Authorized>
<NotAuthorized>
<RadzenButton Text="login" Click="GoToRegister"></RadzenButton>
</NotAuthorized>
<Authorizing>
<h1>Authentication in progress</h1>
<p>Only visible while authentication is in progress.</p>
</Authorizing>
What's wrong with that?
回答1:
In your Login page you should inject LocalAuthenticationStateProvider
@inject LocalAuthenticationStateProvider LocalAuthStateProvider
After doing:
await storageService.SetItemAsync("User", userInfo);
which I guess, storing the user's information, let subscribers, such as the CascadingAuthenticationState
, know that the Authentication state has been changed.
This is done so:
LocalAuthStateProvider.NotifyAuthenticationStateChanged();
Your custom AuthenticationStateProvider should be like the following:
public async override Task<AuthenticationState> GetAuthenticationStateAsync()
{
ClaimsIdentity identity;
if (await _storageService.ContainKeyAsync("User"))
{
var userInfo = await _storageService.GetItemAsync<LocalUserInfo>
("User");
var claims = new[]
{
new Claim("Email", userInfo.Email),
new Claim("FirstName", userInfo.FirstName),
new Claim("LastName", userInfo.LastName),
new Claim("AccessToken", userInfo.AccessToken),
new Claim(ClaimTypes.NameIdentifier, userInfo.Id),
};
identity = new ClaimsIdentity(claims );
}
else
{
identity = new ClaimsIdentity();
}
return await Task.FromResult(new AuthenticationState(new
ClaimsPrincipal(identity)));
}
public void NotifyAuthenticationStateChanged()
{
NotifyAuthenticationStateChanged(GetAuthenticationStateAsync());
}
And your Startup class should be like this:
public void ConfigureServices(IServiceCollection services)
{
services.AddAuthentication();
services.AddAuthorization();
// services.AddAuthorizationCore();
services.AddScoped<LocalAuthenticationStateProvider>();
services.AddScoped<AuthenticationStateProvider>(provider => provider.GetRequiredService<LocalAuthenticationStateProvider>());
}
Hope this helps...
来源:https://stackoverflow.com/questions/62332754/why-my-authentication-state-provider-not-work