使用托管身份从本地Azure功能查询Azure SQL数据库

时间:2019-08-14 07:59:32

标签: azure-active-directory azure-sql-database azure-functions azure-managed-identity

我想使用托管身份(即连接到Visual Studio的用户的身份,而不是在我的连接字符串中提供UserId和密码)从在调试中的计算机上执行的Azure函数中查询Azure SQL数据库。

我在Microsoft文档上遵循了this tutorial,因此我的Azure SQL Server拥有一个AD用户作为admin,这使我可以授予我使用Azure Function Identity和其中的用户创建的Azure AD组的权限(db_datareader) (以及我在Azure中部署的Function App)。

如果我在Azure功能中在Azure中部署和运行,它可以查询我的数据库,并且一切正常。但是,当我在本地运行Azure函数时,出现以下错误:

  

用户'NT AUTHORITY \ ANONYMOUS LOGON'登录失败。

我的函数的代码如下:

    public async Task<IActionResult> Run(
        [HttpTrigger(AuthorizationLevel.Function, "get", "post", Route = "test")] HttpRequest req,
        ILogger log)
    {
        log.LogInformation("C# HTTP trigger function processed a request.");


        using (var connection = new SqlConnection(Environment.GetEnvironmentVariable("sqlConnectionString")))
        {
            connection.AccessToken = await (new AzureServiceTokenProvider()).GetAccessTokenAsync("https://database.windows.net");
            log.LogInformation($"Access token : {connection.AccessToken}");
            try
            {
                await connection.OpenAsync();
                var rows = await connection.QueryAsync<Test>("select top 10 * from TestTable");
                return new OkObjectResult(rows);
            }
            catch (Exception e)
            {
                throw e;
            }

        }
    }

该代码正确检索了令牌,该错误发生在第await connection.OpenAsync()行。

如果在Azure Data Studio中使用与连接到Visual Studio的用户相同的用户打开数据库(该用户是具有数据库权限的AD组的成员),则可以连接和查询数据库而没有任何问题。

这是已知问题还是我在这里遗漏了什么?

2 个答案:

答案 0 :(得分:0)

您本地计算机的IP地址是否列入白名单?

https://docs.microsoft.com/en-us/azure/sql-database/sql-database-firewall-configure

White-list IP

答案 1 :(得分:0)

尝试了特定的情况后,我测试了很多方法来尝试使其在本地运行。这不起作用,给出的错误信息与您相同。

当可能的解决方案出现时,我与一些人进行了讨论。我测试了它:它有效!

在我的情况下,主要问题是我的订阅(和我的用户)是一个Microsoft帐户(Outlook)。因此,您需要在tenantId调用中指定GetAccessTokenAsync()

显然,对于托管身份,您不必指定tenantId。对于用户,最好明确指定它。如果是个人MS帐户,则必须指定该帐户。

我的代码(某种):

var tokenProvider = new AzureServiceTokenProvider();

using (var connection = new SqlConnection(CONNECTIONSTRING))
using (var command = new SqlCommand(QUERY, connection))
{
    connection.AccessToken = await tokenProvider.GetAccessTokenAsync("https://database.windows.net/", "<YOUR_TENANT_ID>");

    await connection.OpenAsync();
    var result = (await command.ExecuteScalarAsync()).ToString();

    return new OkObjectResult(result);
}

此解决方案已经过测试,并且在指定tenantId(或目录ID,租户的GUID)和'onmicrosoft'名称(xxx.onmicrosoft.com)时都可以使用。