使用RemoteAuthenticatorView OnLogInSucceded将显示第二个AzureAD登录对话框



很难理解发生了什么,我真的需要一些思考和输入。拜托,我不太善于用文字描述问题出在哪里,所以请温柔一点。

我有一个Blazor wasm前端和一个Azure Function后端
我做了一个标准的,没有什么特别的,Azure AD登录。在代码的后面,我使用承载令牌连接AzFunction,它就工作了。AzFunction评估令牌并识别用户以供进一步处理。我应该提到的是,AzFunction连接到Graph和其他API。

所以一切都很好,这是我的问题
我想在登录时连接到AzFuntion,以获取一些用户配置文件信息。为了调试,我只做了一个按钮,一切都正常。

然后我移动了";按钮代码";到Authenticator.razor.中RemoteAuthenticatorView OnLogInSuccessed调用的方法

<RemoteAuthenticatorView Action="@Action" LogInFailed="LogInFailedFragment" OnLogInSucceeded="LoginComplete" />

这是我的问题:使用OnLogInSucceded,我得到了2个Azure AD登录,我必须对其进行响应。在第一个登录之后,它直接进入第二个。只是因为我把代码从一个按钮移到了OnLogInSucceded。当我调试时,我清楚地看到令牌在连接到AzFunction之前就已经存在了。

此外,当我在visual studio中从OnLogInSucceded调用的LoginComplete函数处设置断点,并保持几秒钟时,它只需一个登录对话框即可完成登录过程。

有人能帮我理解为什么吗?

任何关于更好的指针请放在";获取用户配置文件";密码我需要的是运行的代码,所以当登录完成时,只需一次登录就可以检索用户配置文件信息。

编辑:
代码似乎有更好的解决方案,但我仍然不明白是什么让第二次登录出现。。。这也是我提出这个问题的主要原因。

多亏了Raymond,我也得到了一个很好的指导,并制作了一个组件来加载这种类型的数据。当组件初始化时,我不得不将事件和加载结合起来。我仍然觉得M$应该而且可能会找到更好的方法来做到这一点。

对于这个应用程序,我使用Azure B2C进行身份验证,并且我使用重定向而不是弹出。当我初始化userstate时,我会调用获取用户配置文件的api,或者如果是新用户,我会创建一个。

InitialDataLoader.razor

@implements IDisposable
@inject NavigationManager _navigationManager
@inject UserState _userState
@inject AuthenticationStateProvider _authenticationStateProvider
@ChildContent
@code {
[Parameter]
public RenderFragment ChildContent { get; set; }
// The event can trigger multiple times when being redirected from the Authentication page to wherever you're going.
// So we use this to check.
public bool hasRunInit;
protected override async Task OnInitializedAsync()
{
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss:fff") + " InitialDataLoader -> OnInitializedAsync -> " + _navigationManager.Uri);
// This component is already loaded and initialized on the Authentication page, so we have to subscribe to this event to
// check when the user bounces back from Azure B2C and gets logged in. In that case, we do the initial load in on the event
_authenticationStateProvider.AuthenticationStateChanged += this.OnAuthenticationStateChanged;

// If the user is authenticated and reloads the page in the browser, the event won't trigger so we can do the initial load here.
var user = (await _authenticationStateProvider.GetAuthenticationStateAsync()).User;
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss:fff") + " InitialDataLoader -> OnInitializedAsync -> IsUserAuthenticated: " + user.Identity.IsAuthenticated);
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss:fff") + " InitialDataLoader -> OnInitializedAsync -> IsStateInitialized: " + _userState.IsInitialized);
if (user.Identity.IsAuthenticated && !_userState.IsInitialized)
{
hasRunInit = true;
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss:fff") + " InitialDataLoader -> OnInitializedAsync -> InitUser");
await _userState.InitializeAsync(this);
}
}
void IDisposable.Dispose()
{
_authenticationStateProvider.AuthenticationStateChanged -= this.OnAuthenticationStateChanged;
}
private async void OnAuthenticationStateChanged(Task<AuthenticationState> task)
{
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss:fff") + " InitialDataLoader -> OnAuthenticationStateChanged -> " + _navigationManager.Uri);
var user = (await task).User;
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss:fff") + " InitialDataLoader -> OnAuthenticationStateChanged -> IsUserAuthenticated: " + user.Identity.IsAuthenticated);
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss:fff") + " InitialDataLoader -> OnAuthenticationStateChanged -> IsStateInitialized: " + _userState.IsInitialized);
if (user.Identity.IsAuthenticated && !_userState.IsInitialized)
{
if (!hasRunInit)
{
hasRunInit = true;
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss:fff") + " CascadingAppStateProvider -> OnInitializedAsync -> InitUser");
await _userState.InitializeAsync(this);
}
else
{
Console.WriteLine(DateTime.Now.ToString("hh:mm:ss:fff") + " InitialDataLoader -> OnInitializedAsync -> Init has already been triggered!");
}
}
}
}

App.razor

<CascadingAuthenticationState>
<InitialDataLoader>
<Router AppAssembly="@typeof(Program).Assembly">
<Found Context="routeData">
<AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)">
<Authorizing>
------------- Authorizing.. ------------------
</Authorizing>
<NotAuthorized>
@if (!context.User.Identity.IsAuthenticated)
{
<RedirectToLogin />
}
else
{
<p>You are not authorized to access this resource.</p>
}
</NotAuthorized>
</AuthorizeRouteView>
</Found>
<NotFound>
<LayoutView Layout="@typeof(MainLayout)">
<p>Sorry, there's nothing at this address.</p>
</LayoutView>
</NotFound>
</Router>
</InitialDataLoader>
</CascadingAuthenticationState>

当用户从网关返回时,组件在应用程序对用户进行身份验证之前进行初始化。然后,该事件触发两次,一次用于身份验证页面,另一次用于您正在查看的任何页面。

感谢Zack Blazor Webassembly Authenticated Event,我收到了良好的指示,并阅读了AuthenticationStateChanged Event上的Microsoft页面。它还简化了我的代码,因为我现在在UserProfile组件中有UserProfile的检索,而不是Authentication.razor。

@inject AuthenticationStateProvider AuthenticationStateProvider
private void OnAuthenticationStateChanged(Task<AuthenticationState> task)
{
if(task.IsCompletedSuccessfully)
{
GetUserProfile();
}
}

不确定这是否是";最后的代码";,但它确实有效,在我看来是一条可行的道路。

最新更新