Соединение EF Core с Azure SQL с управляемой идентификацией

Я использую EF Core для подключения к базе данных SQL Azure, развернутой в службах приложений Azure. Я использую токен доступа (полученный через управляемые удостоверения) для подключения к базе данных SQL Azure.

Вот как я это делаю:

Startup.cs:

public void ConfigureServices(IServiceCollection services)
{
    //code ignored for simplicity
    services.AddDbContext<MyCustomDBContext>();

    services.AddTransient<IDBAuthTokenService, AzureSqlAuthTokenService>();
}

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);
    }
}

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;
    }
}

Это отлично работает, и я могу получить данные из базы данных. Но я не уверен, что это правильный способ сделать это.

Мои вопросы:

  1. Это правильный способ сделать это или у него будут проблемы с производительностью?
  2. Нужно ли беспокоиться об истечении срока действия токена? Я не кеширую токен на данный момент.
  3. Есть ли у EF Core лучший способ справиться с этим?

Ответ 1

Это правильный способ сделать это или у него будут проблемы с производительностью?

Это правильный путь. OnConfiguring вызывается для каждого нового DbContext, поэтому, если у вас нет долгоживущих экземпляров DbContext, это правильный шаблон.

Нужно ли беспокоиться об истечении срока действия токена? Я не кеширую токен на данный момент.

AzureServiceTokenProvider заботится о кэшировании.

Есть ли у EF Core лучший способ справиться с этим?

Настройка SqlConnection.AccessToken в настоящее время является единственным способом использования AAD Auth в SqlClient для .NET Core.

Ответ 2

У вас есть ссылка на рабочий код github? можешь поделиться, пожалуйста? Я сталкиваюсь с проблемами с consturctor datacontext.

Thansk!

Ответ 3

Для разработчиков, использующих .net Framework для управляемой идентификации, приведенный ниже код может быть полезен для установления соединения сущностей.

app config file
<add key="ResourceId" value="https://database.windows.net/" />
<add key="Con" value="data source=tcp:sampledbserver.database.windows.net,1433;initial catalog=sampledb;MultipleActiveResultSets=True;Connect Timeout=30;" />

c# file
using System;
using System.Configuration;
using System.Data.Entity.Core.EntityClient;
using System.Data.Entity.Core.Metadata.Edm;
using System.Data.SqlClient;
using Microsoft.IdentityModel.Clients.ActiveDirectory;
using Microsoft.Azure.Services.AppAuthentication;

public static  EntityConnection GetEntityConnectionString()
    {
        MetadataWorkspace workspace = new MetadataWorkspace(
           new string[] { "res://*/" },
           new Assembly[] { Assembly.GetExecutingAssembly() });

         SqlConnection sqlConnection = new SqlConnection(Con);

         var result = (new 
         AzureServiceTokenProvider()).GetAccessTokenAsync(ResourceId).Result;
        sqlConnection.AccessToken = result ?? throw new 
        InvalidOperationException("Failed to obtain the access token");
        EntityConnection entityConnection = new EntityConnection(workspace, 
        sqlConnection);
        return entityConnection;
    }