use*_*744 17 azure-active-directory entity-framework-core azure-sql-database ef-core-2.2
我正在使用EF Core连接到已部署到Azure App Services的Azure SQL数据库。我正在使用访问令牌(通过托管身份获取)连接到Azure SQL数据库。
这是我的做法:
Startup.cs:
public void ConfigureServices(IServiceCollection services)
{
//code ignored for simplicity
services.AddDbContext<MyCustomDBContext>();
services.AddTransient<IDBAuthTokenService, AzureSqlAuthTokenService>();
}
Run Code Online (Sandbox Code Playgroud)
MyCustomDBContext.cs
public partial class MyCustomDBContext : DbContext
{
public IConfiguration Configuration { get; }
public IDBAuthTokenService authTokenService { get; set; }
public CortexContext(IConfiguration configuration, IDBAuthTokenService tokenService, DbContextOptions<MyCustomDBContext> options)
: base(options)
{
Configuration = configuration;
authTokenService = tokenService;
}
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
SqlConnection connection = new SqlConnection();
connection.ConnectionString = Configuration.GetConnectionString("defaultConnection");
connection.AccessToken = authTokenService.GetToken().Result;
optionsBuilder.UseSqlServer(connection);
}
}
Run Code Online (Sandbox Code Playgroud)
AzureSqlAuthTokenService.cs
public class AzureSqlAuthTokenService : IDBAuthTokenService
{
public async Task<string> GetToken()
{
AzureServiceTokenProvider provider = new AzureServiceTokenProvider();
var token = await provider.GetAccessTokenAsync("https://database.windows.net/");
return token;
}
}
Run Code Online (Sandbox Code Playgroud)
这工作正常,我可以从数据库中获取数据。但是我不确定这是否是正确的方法。
我的问题:
rom*_*mar 16
虽然该方法通常是正确的,因为除了必须编写设置AccessToken连接的自定义代码之外别无他法,但您的实现中有几个问题可以通过使用 a 来避免,DbConnectionInterceptor我将在下面描述。这两个问题是:
.Result在等待访问令牌时使用阻塞。更好的替代方法是使用 EF Core 支持的拦截器。你将从这样的开始DbContext:
public class MyCustomDbContextFactory : IMyCustomDbContextFactory
{
private readonly string _connectionString;
private readonly AzureAuthenticationInterceptor _azureAuthenticationInterceptor;
public MyCustomDbContextFactory(DbContextFactoryOptions options, AzureAuthenticationInterceptor azureAuthenticationInterceptor)
{
_connectionString = options.ConnectionString;
_azureAuthenticationInterceptor = azureAuthenticationInterceptor;
}
public MyCustomDbContext Create()
{
var optionsBuilder = new DbContextOptionsBuilder<MyCustomDbContext>();
optionsBuilder
.UseSqlServer(_connectionString)
.AddInterceptors(_azureAuthenticationInterceptor);
return new MyCustomDbContext(optionsBuilder.Options);
}
}
Run Code Online (Sandbox Code Playgroud)
这是拦截器的实现:
public class AzureAuthenticationInterceptor : DbConnectionInterceptor
{
private const string AzureDatabaseResourceIdentifier = "https://database.windows.net";
private readonly AzureServiceTokenProvider _azureServiceTokenProvider;
public AzureAuthenticationInterceptor(AzureServiceTokenProvider azureServiceTokenProvider) : base()
{
_azureServiceTokenProvider = azureServiceTokenProvider;
}
public override async ValueTask<InterceptionResult> ConnectionOpeningAsync(DbConnection connection, ConnectionEventData eventData, InterceptionResult result, CancellationToken cancellationToken = default)
{
if (connection is SqlConnection sqlConnection)
{
sqlConnection.AccessToken = await GetAccessToken();
}
return result;
}
public override InterceptionResult ConnectionOpening(DbConnection connection, ConnectionEventData eventData, InterceptionResult result)
{
if (connection is SqlConnection sqlConnection)
{
sqlConnection.AccessToken = GetAccessToken().Result;
}
return result;
}
private Task<string> GetAccessToken() => _azureServiceTokenProvider.GetAccessTokenAsync(AzureDatabaseResourceIdentifier);
}
Run Code Online (Sandbox Code Playgroud)
这是配置服务的方法:
services.AddSingleton(new DbContextFactoryOptions(connection_string));
services.AddSingleton(new AzureAuthenticationInterceptor(new AzureServiceTokenProvider()));
Run Code Online (Sandbox Code Playgroud)
最后,这是DbContext在存储库中实例化对象的方法:
public async Task<IEnumerable<MyCustomEntity>> GetAll()
{
using var context = _notificationsDbContextFactory.Create(); // Injected in ctor
var dbos = await context.MyCustomEntity.ToListAsync();
return ... // something;
}
Run Code Online (Sandbox Code Playgroud)
Dav*_*oft 10
这是正确的方法还是会出现性能问题?
那是正确的方法。每个新的DbContext都会调用OnConfiguring,因此,假设您没有任何长期存在的DbContext实例,那么这是正确的模式。
我需要担心令牌到期吗?截至目前,我还没有缓存令牌。
AzureServiceTokenProvider 负责缓存。
EF Core是否有更好的方法来解决此问题?
当前,设置SqlConnection.AccessToken是在SqlClient for .NET Core中使用AAD Auth的唯一方法。
| 归档时间: |
|
| 查看次数: |
1497 次 |
| 最近记录: |