在类中实例化 IConfidentialClientApplication 是一种不好的做法吗?



例如,我在应用程序配置中注册了一个临时服务AuthorizationClient,它充当我的 API 和 Azure 之间授权令牌的客户端中介。在里面,有一个IConfidentialClientApplication对象属性:

public class AuthorizationClient : IAuthorizationClient
{
private readonly string[] _resourceIds;
private IConfidentialClientApplication App;
public AuthorizationClient(IAuthenticationConfig AuthenticationConfig, IConfiguration configuration)
{
var scope = "/.default";
var resourceId = "api://" + configuration[AuthenticationConfig.ResourceID] + scope;
var clientId = configuration[AuthenticationConfig.ClientID];
var clientSecret = configuration[AuthenticationConfig.ClientSecret];            
var instance = AuthenticationConfig.Instance;
var tenant = configuration[AuthenticationConfig.AzureTenantId];        
var authority = string.Format(CultureInfo.InvariantCulture, instance, tenant);

_resourceIds = new string[] { resourceId };
try
{
App = ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithAuthority(new Uri(authority))                
.Build();
}
catch(Exception ex)
{
//TODO logger
}
}
...
}

在此类的其他地方,我有成功获取令牌、检查令牌缓存等的方法。

但是,当我看到正在使用IConfidentialClientApplication的文档或存储库时,它总是作为服务添加到应用程序级别,而不是在另一个对象中。我这样做的方式是否存在潜在的陷阱?

如果每个客户端请求都实例化一个新的,则IConfidentialClientApplication似乎相当重/很大,但是由于我已经在应用程序级服务的对象中实例化了它,因此每个生命周期似乎只创建了一个。

实例化目标类中的依赖项是一种代码异味

陷阱:与实现细节的紧密耦合和显式依赖原则违规。

这些将使孤立地维护和测试您的类变得困难。

这些设计问题可以通过应用单一责任原则/关注点分离和显式依赖原则来修复,使您的代码更加可靠

创建一个类来存储客户端选项。根据提供的示例,它可能看起来像这样

public class AuthorizationClientOptions {
public string[] ResourceIds { get; set; }
}

重构类以显式依赖于执行其功能的实际需要什么

public class AuthorizationClient : IAuthorizationClient {
private readonly string[] _resourceIds;
private readonly IConfidentialClientApplication app;
public AuthorizationClient(IConfidentialClientApplication app, IOptions<AuthorizationClientOptions> options) {
this.app = app;
_resourceIds = options.Value.ResourceIds;
}

// ...
}

在组合根目录中配置必要的实现详细信息(启动)

//...
IConfiguration Configuration; //Populated either via constructor injection or manually 
public void ConfigureServices(IServiceCollection services) {
//...

//Configure options
services.AddOptions<AuthorizationClientOptions>()
.Configure<IAuthenticationConfig,IConfiguration>(
(o, authConfig, config) => {
var scope = "/.default";
var resourceId = "api://" + config[authConfig.ResourceID] + scope;
o.ResourceIds = new string[] { resourceId };
});

//Configure dependency using factory delegate
services.AddSingleton<IConfidentialClientApplication>(sp => {
IAuthenticationConfig AuthenticationConfig = sp.GetRequiredService<IAuthenticationConfig>();

var instance = Configuration.Instance;
var tenant = Configuration[AuthenticationConfig.AzureTenantId];
var authority = string.Format(CultureInfo.InvariantCulture, instance, tenant);

var clientId = Configuration[AuthenticationConfig.ClientID];
var clientSecret = Configuration[AuthenticationConfig.ClientSecret];

return ConfidentialClientApplicationBuilder.Create(clientId)
.WithClientSecret(clientSecret)
.WithAuthority(new Uri(authority))
.Build();
});

services.AddScoped<IAuthorizationClient, AuthorizationClient>();

//...
}

如果每个客户端请求实例化一个新IConfidentialClientApplication,则似乎相当重/很大

上面示例中的IConfidentialClientApplication是作为单一实例创建的,因此在实例化时将产生一次性成本。

相关内容

最新更新