MSI 可以使用 EF Code First 吗?

Posted

技术标签:

【中文标题】MSI 可以使用 EF Code First 吗?【英文标题】:Can MSI work with EF CodeFirst? 【发布时间】:2018-10-07 19:58:32 【问题描述】:

我已经在这个问题上卡住了很长一段时间,没有运气靠自己推进它。

我正在尝试使用 MSI 令牌从 Azure 应用服务连接到 EF CodeFirst 托管数据库。

当我使用 ARM 部署应用服务时,我生成了一个输出,以确保它创建了一个服务主体:

 
  "principalId":"98f2c1f2-0a86-4ff1-92db-d43ec0edxxxx","
  tenantId":"e6d2d4cc-b762-486e-8894-4f5f440dxxxx",
  "type":"SystemAssigned"
 

在 Kudu 中,环境变量显示它正在安装:

MSI_ENDPOINT = http://127.0.0.1:41239/MSI/token/
MSI_SECRET = 7C1B16Fxxxxxxxxxxxxx

我在 Azure 门户中提供了如下连接字符串:

Data Source=nzmoebase0000bt.database.windows.net;Initial Catalog=nzmoebase0001bt;Connect Timeout=300;MultipleActiveResultSets=False;Encrypt=True;TrustServerCertificate=False;Connection Timeout=300;

我已将主体作为所有者添加到数据库中。

Note: I cannot do the same for the master db.

token 被添加到 DbContext 中,如下所示:

正在使用以下方式添加令牌:

    static async Task AttachAccessTokenToDbConnection(IDbConnection dbConnection)
    
        SqlConnection sqlConnection = dbConnection as SqlConnection;
        if (sqlConnection == null)
        
            return;
        
        string msiEndpoint = Environment.GetEnvironmentVariable("MSI_ENDPOINT");
        if (string.IsNullOrEmpty(msiEndpoint))
        
            return;
        

        var msiSecret = Environment.GetEnvironmentVariable("MSI_SECRET");
        if (string.IsNullOrEmpty(msiSecret))
        
            return;
        

        // To get around:
        // "Cannot set the AccessToken property if 'UserID', 'UID', 'Password', or 'PWD' has been specified in connection string."
        var terms = new[] "UserID","Password","PWD=","UID=" ;
        string connectionString = dbConnection.ConnectionString;

        foreach (var term in terms)
        
            if (connectionString.Contains(term, StringComparison.InvariantCultureIgnoreCase))
            
                return;
            
        

        string accessToken = await AppCoreDbContextMSITokenFactory.GetAzureSqlResourceTokenAsync();
        sqlConnection.AccessToken = accessToken;
    

启用跟踪后,令牌为:

 .eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI....

使用 jwt.io 解码得到:


  "typ": "JWT",
  "alg": "RS256",
  "x5t": "FSimuFrFNoC0sJXGmv13nNZceDc",
  "kid": "FSimuFrFNoC0sJXGmv13nNZceDc"
.
  "aud": "https://database.windows.net/",
  "iss": "https://sts.windows.net/e6d2d4cc-b762-486e-8894-4f5f440dxxxx/",
  "iat": 1522783025,
  "nbf": 1522783025,
  "exp": 1522786925,
  "aio": "Y2NgYPjNdyJd9zrzpLavJSEzNIuPAAA=",
  "appid": "d1057cea-461b-4946-89a9-d76439c2xxxx",
  "appidacr": "2",
  "e_exp": 262800,
  "idp": "https://sts.windows.net/e6d2d4cc-b762-486e-8894-4f5f440dxxxx/",
  "oid": "98f2c1f2-0a86-4ff1-92db-d43ec0edxxxx",
  "sub": "98f2c1f2-0a86-4ff1-92db-d43ec0edxxxx",
  "tid": "e6d2d4cc-b762-486e-8894-4f5f440dxxxx",
  "uti": "59bqKWiSL0Gf0bTCI0AAAA",
  "ver": "1.0"
.[Signature]

我根据网上的一些建议添加了Persist Security Info = True,但没有发现任何效果。

Data Source=nzmoebase0000bt.database.windows.net;Initial Catalog=nzmoebase0001bt;MultipleActiveResultSets=False;Persist Security Info = True;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;

我得到的错误是:

[InvalidOperationException: This operation requires a connection to the 'master' database. Unable to create a connection to the 'master' database because the original database connection has been opened and credentials have been removed from the connection string. Supply an unopened connection.]

有没有人使用 CodeFirst、Migrations 和 MSI 连接到数据库?在这一点上,在真正被卡住了几个星期之后,我开始怀疑这是否可能。

感谢您的帮助——即使只是证明它可以工作,对于初学者来说。

【问题讨论】:

已经回答了吗?我的一位同事遇到了完全相同的问题。 有人找到解决方案吗?我碰到这个.... 【参考方案1】:

您可以像这样在 sql 连接上设置访问令牌:

    安装Microsoft.Azure.Services.AppAuthentication nuget 包

    像这样设置你的上下文类:

    public class MyDatabaseContext : DbContext
    
        public MyDatabaseContext(DbContextOptions<MyDatabaseContext> options)
            : base(options)
        
            // Get the db connection
            var connection = (SqlConnection)Database.GetDbConnection();
    
            // Add the access token
            connection.AccessToken = new AzureServiceTokenProvider()
                .GetAccessTokenAsync("https://database.windows.net/")
                .ConfigureAwait(false).GetAwaiter().GetResult();
        
    
        public DbSet<MyTable> MyTable  get; set; 
    
    

【讨论】:

【参考方案2】:

不幸的是,据我所知,没有。项目不得不退回到不安全的用户名/密码加载连接字符串的主要绊脚石。

【讨论】:

以上是关于MSI 可以使用 EF Code First 吗?的主要内容,如果未能解决你的问题,请参考以下文章

在 EF6 Code First 中支持表值函数吗?

[EF]vs15+ef6+mysql code first方式

EF Code-First 中的种子方法

ef code first db first 哪种好

使用 EF Code First + Mysql

ef code first 怎样指定哪些类生成数据表?那些不生成数据表?