我正在使用一个使用Azure AD B2C进行身份验证的.NET MAUI应用程序。
我的应用程序中有多个Azure AD B2C策略(正常运行的注册并希望添加密码重置策略),并且我需要为不同的策略使用不同的IPublicClientApplication
示例(因为它们使用不同的用户流)。
我尝试了几种方法来配置依赖注入,但遇到了两个服务最终使用同一个IPublicClientApplication
示例的问题。
以下是工作正常的登录服务:
public class AuthServiceB2CSignInSignUp : IAuthService
{
private readonly IPublicClientApplication _signInApp;
public AuthServiceB2CSignInSignUp(IPublicClientApplication signInApp)
{
_signInApp = signInApp;
}
public Task<AuthenticationResult?> SignInInteractively(CancellationToken cancellationToken)
{
return _signInApp
.AcquireTokenInteractive(Constants.Scopes)
.ExecuteAsync(cancellationToken);
}
public async Task<AuthenticationResult?> AcquireTokenSilent(CancellationToken cancellationToken)
{
try
{
var accounts = await _signInApp.GetAccountsAsync(Constants.SignInPolicy);
var firstAccount = accounts.FirstOrDefault();
if (firstAccount is null)
{
return null;
}
return await _signInApp.AcquireTokenSilent(Constants.Scopes, firstAccount)
.ExecuteAsync(cancellationToken);
}
catch (MsalUiRequiredException)
{
return null;
}
}
public async Task LogoutAsync(CancellationToken cancellationToken)
{
var accounts = await _signInApp.GetAccountsAsync();
foreach (var account in accounts)
{
await _signInApp.RemoveAsync(account);
}
}
}
下面是密码重置,如果我自己运行它也可以正常工作:
public class AuthServiceB2CResetPassword : IAuthServiceB2CResetPassword
{
private readonly IPublicClientApplication _resetApp;
public AuthServiceB2CResetPassword(IPublicClientApplication resetApp)
{
_resetApp = resetApp;
}
public Task<AuthenticationResult?> SignInInteractively(CancellationToken cancellationToken)
{
return _resetApp
.AcquireTokenInteractive(Constants.Scopes)
.ExecuteAsync(cancellationToken);
}
public async Task<AuthenticationResult?> AcquireTokenSilent(CancellationToken cancellationToken)
{
try
{
var accounts = await _resetApp.GetAccountsAsync(Constants.SignInPolicy);
var firstAccount = accounts.FirstOrDefault();
if (firstAccount is null)
{
return null;
}
return await _resetApp.AcquireTokenSilent(Constants.Scopes, firstAccount)
.ExecuteAsync(cancellationToken);
}
catch (MsalUiRequiredException)
{
return null;
}
}
}
这是我注册它们的方式:
mauiAppBuilder.Services.AddScoped<IAuthService, AuthServiceB2CSignInSignUp>();
mauiAppBuilder.Services.AddScoped<IPublicClientApplication>(sp =>
{
var app = PublicClientApplicationBuilder
.Create(Constants.ClientId)
.WithIosKeychainSecurityGroup(Constants.IosKeychainSecurityGroups)
.WithRedirectUri($"msal{Constants.ClientId}://auth")
.WithB2CAuthority(Constants.AuthoritySignIn)
.Build();
return app;
});
mauiAppBuilder.Services.AddScoped<IAuthServiceB2CResetPassword, AuthServiceB2CResetPassword>();
mauiAppBuilder.Services.AddScoped<IPublicClientApplication>(sp =>
{
var passwordResetApp = PublicClientApplicationBuilder
.Create(Constants.ClientId)
.WithIosKeychainSecurityGroup(Constants.IosKeychainSecurityGroups)
.WithRedirectUri($"msal{Constants.ClientId}://auth")
.WithB2CAuthority(Constants.AuthorityPasswordReset)
.Build();
return passwordResetApp;
});
在我的登录视图模型中,我将它们注入到构造函数中:
private readonly IAuthService _signupService;
private readonly IAuthServiceB2CResetPassword _passwordResetService;
public LoginViewModel(IAuthService signupService, IAuthServiceB2CResetPassword passwordResetService)
{
_signupService = signupService;
_passwordResetService = passwordResetService;
}
//do something here
但是,无论IPublicClientApplication
的最后一个注册示例是什么,它总是覆盖另一个注册示例,因为PublicClientApplication
来自Microsoft.Identity.Client
,我真的不明白应该采取什么方法来拥有两个不同的IPublicClientApplication
对象,一个用于密码重置,一个用于登录。
我尝试更改顺序,但也没有帮助,尽管配置了IPublicClientApplication
的命名示例,但两个服务(_signupService
和_passwordResetService
)最终使用相同的IPublicClientApplication
示例。
我已经尝试命名注册,但它似乎不像预期的那样工作。.NET MAUI的依赖注入系统中是否有限制阻止了这种设置,或者我的配置中缺少了什么?
在.NET MAUI应用程序中,为不同服务的多个命名IPublicClientApplication
示例配置依赖注入的正确方法是什么?我也试着找到一些官方的Azure B2C MAUI示例,但Azure-Samples中的示例甚至没有实现密码重置,只有登录注册。我想同时实施这两项措施。
2条答案
按热度按时间0qx6xfy61#
这不是MAUI特有的,这只是Microsoft-provided .NET dependency injection system的工作方式。
在Microsoft系统中,当你为同一个接口注册额外的实现时(有一些警告),它会将所有的实现添加到服务集合中 *,但是 * 只有当你将它们注入为
IEnumerable<T>
时,它才会返回这些实现。如果你只注入一个接口,那么它将永远是最后一个注册的实现。举例来说:
如果你需要以你描述的方式注入一个特定的实现,那么你可以使用微软的DI系统,比如this Stack Overflow answer,或者你可以集成更高级的DI容器,比如Autofac,它支持命名服务和the factory pattern。
cs7cruho2#
根据@Dave D的建议,我使用工厂模式进行了重构(该帖子的链接也非常有用),我将把它放在这里,以防有人想要重用。
每个用户流的单独类
密码重置
这样的注册
然后,在注入之后,可以单独访问每个服务