-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Description
Is there an existing issue for this?
- I have searched the existing issues
Describe the bug
We have a Blazor Web Assembly Client that needs OIDC and custom login together, the existing solutions from the Microsoft documentations work fine when used separately,
builder.Services.AddOidcAuthentication(x =>
{
//options
});
Or
builder.Services.AddScoped<AuthenticationStateProvider, CustomAuthenticationStateProvider>();
But when we use them together, this exception thrown:
Unhandled exception rendering component: Specified cast is not valid.
System.InvalidCastException: Specified cast is not valid.
I have seen a similar issues here and there but there's no solution using these standard components without implementing multiple interfaces like IRemoteAuthenticationService & IAccessTokenProvider to CustomAuthenticationStateProvider.
Do you plan an update so we can use these together, if not can you point out a work around?
Expected Behavior
No response
Steps To Reproduce
This is a sample CustomProvider, we want to be able to login this way as well as with OIDC
public class CustomAuthenticationStateProvider : AuthenticationStateProvider, IDisposable
{
private readonly UserService _userService;
public User CurrentUser { get; private set; } = new User(string.Empty, string.Empty);
public CustomAuthenticationStateProvider(UserService userService)
{
_userService = userService;
AuthenticationStateChanged += OnAuthenticationStateChangedAsync;
}
public async Task LoginAsync(IClinician clinician)
{
var principal = new ClaimsPrincipal();
var user = _userService.ConvertClinicianToUser(clinician);
if (user is not null)
{
await _userService.PersistUserToBrowserAsync(user);
principal = User.ToClaimsPrincipal(user);
}
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(principal)));
}
public async Task LogoutAsync()
{
await _userService.ClearBrowserUserDataAsync();
NotifyAuthenticationStateChanged(Task.FromResult(new AuthenticationState(new())));
}
public override async Task<AuthenticationState> GetAuthenticationStateAsync()
{
var principal = new ClaimsPrincipal();
var user = await _userService.FetchUserFromBrowserAsync();
if (user is not null)
{
bool userExists = await _userService.CheckIfUserExistsInDatabaseAsync(user);
if (userExists)
{
principal = User.ToClaimsPrincipal(user);
CurrentUser = user;
}
}
return new AuthenticationState(principal);
}
public void Dispose()
{
AuthenticationStateChanged -= OnAuthenticationStateChangedAsync;
}
private async void OnAuthenticationStateChangedAsync(Task<AuthenticationState> task)
{
var authenticationState = await task;
if (authenticationState is not null)
{
CurrentUser = User.FromClaimsPrincipal(authenticationState.User);
}
}
}
Exceptions (if any)
crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
Unhandled exception rendering component: Specified cast is not valid.
System.InvalidCastException: Specified cast is not valid.
at Microsoft.Extensions.DependencyInjection.WebAssemblyAuthenticationServiceCollectionExtensions.<>c__11[[Microsoft.AspNetCore.Components.WebAssembly.Authentication.RemoteAuthenticationState, Microsoft.AspNetCore.Components.WebAssembly.Authentication, Version=8.0.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60]].<AddAuthenticationStateProvider>b__1_0(IServiceProvider sp) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitFactory(FactoryCallSite factoryCallSite, RuntimeResolverContext context) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSiteMain(ServiceCallSite callSite, RuntimeResolverContext argument)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitCache(ServiceCallSite callSite, RuntimeResolverContext context, ServiceProviderEngineScope serviceProviderEngine, RuntimeResolverLock lockType)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.VisitScopeCache(ServiceCallSite callSite, RuntimeResolverContext context)
at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteVisitor2[[Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeResolverContext, Microsoft.Extensions.DependencyInjection, Version=8.0.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60],[System.Object, System.Private.CoreLib, Version=8.0.0.0, Culture=neutral, PublicKeyToken=7cec85d7bea7798e]].VisitCallSite(ServiceCallSite callSite, RuntimeResolverContext argument) at Microsoft.Extensions.DependencyInjection.ServiceLookup.CallSiteRuntimeResolver.Resolve(ServiceCallSite callSite, ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.RuntimeServiceProviderEngine.<>c__DisplayClass4_0.<RealizeService>b__0(ServiceProviderEngineScope scope) at Microsoft.Extensions.DependencyInjection.ServiceProvider.GetService(ServiceIdentifier serviceIdentifier, ServiceProviderEngineScope serviceProviderEngineScope) at Microsoft.Extensions.DependencyInjection.ServiceLookup.ServiceProviderEngineScope.GetService(Type serviceType) at Microsoft.AspNetCore.Components.ComponentFactory.<>c__DisplayClass9_0.<CreatePropertyInjector>g__Initialize|1(IServiceProvider serviceProvider, IComponent component) at Microsoft.AspNetCore.Components.ComponentFactory.InstantiateComponent(IServiceProvider serviceProvider, Type componentType, IComponentRenderMode callerSpecifiedRenderMode, Nullable1 parentComponentId)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.InstantiateChildComponentOnFrame(RenderTreeFrame[] frames, Int32 frameIndex, Int32 parentComponentId)
at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewComponentFrame(DiffContext& diffContext, Int32 frameIndex)
at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InitializeNewSubtree(DiffContext& diffContext, Int32 frameIndex)
at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.InsertNewFrame(DiffContext& diffContext, Int32 newFrameIndex)
at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.AppendDiffEntriesForRange(DiffContext& diffContext, Int32 oldStartIndex, Int32 oldEndIndexExcl, Int32 newStartIndex, Int32 newEndIndexExcl)
at Microsoft.AspNetCore.Components.RenderTree.RenderTreeDiffBuilder.ComputeDiff(Renderer renderer, RenderBatchBuilder batchBuilder, Int32 componentId, ArrayRange1 oldTree, ArrayRange1 newTree)
at Microsoft.AspNetCore.Components.Rendering.ComponentState.RenderIntoBatch(RenderBatchBuilder batchBuilder, RenderFragment renderFragment, Exception& renderFragmentException)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.RenderInExistingBatch(RenderQueueEntry renderQueueEntry)
at Microsoft.AspNetCore.Components.RenderTree.Renderer.ProcessRenderQueue()
.NET Version
.NET 8
Anything else?
No response