我有带有系统标识的 Azure Function、带有 Azure 中标识的 Azure Database for PostgreSQL 灵活服务器。出于测试目的,PosttgreSQL 允许公共访问。
我可以使用
DefaultAzureCredential
(az 登录)从我的计算机连接到 PostgreSQL,并将我的电子邮件指定为 Username
中的 NpgsqlConnectionStringBuilder
,即使我认为这应该在没有用户名的情况下工作,因为它是依赖其他 AccessToken 和其中的数据。如果我不指定 Username
,它始终会选择计算机上的用户名,而不是来自 Azure 凭据的用户名。但至少我让它与 Username
一起工作。
当我使用
ManagedIdentityCredential
并将代码部署到该函数时,它找到 PostgreSQL,尝试连接但由于用户名而失败。这是代码和错误消息:
[Function("TestOpenConnection")]
public async Task<IActionResult> RunTestOpenConnectionMisc([HttpTrigger(AuthorizationLevel.Function, "get")] HttpRequest req, CancellationToken cancellationToken)
{
_logger.LogInformation(3009, "C# HTTP trigger TestOpenConnection function processed a request.");
string connectionString = new NpgsqlConnectionStringBuilder
{
Host = "my-xyz-pgsql.postgres.database.azure.com",
Port = 5432,
Database = "my_test_db",
SslMode = SslMode.Require,
// ?? Username
}.ToString();
NpgsqlDataSourceBuilder dataSourceBuilder = new(connectionString);
TimeSpan successRefreshInterval = TimeSpan.FromMinutes(55);
TimeSpan failureRefreshInterval = TimeSpan.FromSeconds(30);
dataSourceBuilder.UsePeriodicPasswordProvider(async (_, ct)
=> await GetAccessTokenAsync(ct), successRefreshInterval, failureRefreshInterval);
await using var dataSource = dataSourceBuilder.Build();
try
{
await dataSource.OpenConnectionAsync(cancellationToken);
}
catch (Exception e)
{
_logger.LogError(2004, e, "FAILED TO OPEN DATABASE CONNECTION");
return new BadRequestObjectResult(e);
}
_logger.LogInformation(3011, "Connection opened successfully");
return new OkObjectResult("Connection opened successfully");
}
private async Task<string> GetAccessTokenAsync(CancellationToken cancellationToken)
{
ManagedIdentityCredential credential = new();
string resource = "https://ossrdbms-aad.database.windows.net";
TokenRequestContext tokenRequestContext = new([$"{resource}/.default"]);
AccessToken fullToken = await credential.GetTokenAsync(tokenRequestContext, cancellationToken).ConfigureAwait(false);
return fullToken.Token;
}
错误:
[Error] FAILED TO OPEN DATABASE CONNECTION
password authentication failed for user "funct-test-postrgre-xyz"
我已经测试了令牌的获取,它可以工作并获取函数身份的正确访问令牌。我尝试了几种连接方式,但我已经没有主意了:
Function name
作为 Username
Service Principal ObjectId
作为 Username
Service Principal ApplicationId
作为 Username
每次我都会得到:
28P01: password authentication failed for user "name/objectId/applicationId"
我需要在 PostreSQL 端设置其他东西吗?
我执行了以下命令:
-- Create a Role for the Enterprise Application:
CREATE ROLE "00000000-0000-0000-0000-000000000000" WITH LOGIN;
-- Grant Privileges to the Role:
GRANT CONNECT ON DATABASE my_test_db TO "00000000-0000-0000-0000-000000000000";
GRANT USAGE ON SCHEMA public TO "00000000-0000-0000-0000-000000000000";
GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA public TO "00000000-0000-0000-0000-000000000000";
-- Configure Default Privileges (Optional):
ALTER DEFAULT PRIVILEGES IN SCHEMA public GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO "00000000-0000-0000-0000-000000000000";
如何验证 PostreSQL 是否设置正确?是服务主体 ApplicationId 还是 ObjectId?
我也遇到了同样的错误。
控制您访问令牌的身份验证过程,使用``
作为参考,请检查此 MS 文档
DefaultAzureCredential
使用所有方法进行身份验证顺序。
如需订购,请查看此MS Document。
这个查询对我有用。
SELECT * FROM pgaadauth_create_principal('<identity_name>', false, false);
#This query assigns these access("create User","Assign Superuser", "Assign Admin")
作为参考,请检查此 MS 文档。
传递数值
Username = <Identity_name>
我的代码:
- 我正在使用动态模型作为用户名
string User = req.Query["User"].FirstOrDefault() ?? Environment.GetEnvironmentVariable("User");
- 确保您已使用
中的查询创建用户Postgresql
using Azure.Core;
using Azure.Identity;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Azure.Functions.Worker;
using Microsoft.Extensions.Logging;
using Npgsql;
using System.Threading;
namespace FunctionApp5
{
public class Function
{
private readonly ILogger<Function> _logger;
public Function(ILogger<Function> logger)
{
_logger = logger;
}
[Function("Function")]
public async Task<IActionResult> Run([HttpTrigger(AuthorizationLevel.Anonymous, "get", "post")] HttpRequest req, CancellationToken cancellationToken)
{
_logger.LogInformation(3009, "C# HTTP trigger TestOpenConnection function processed a request.");
string User = req.Query["User"].FirstOrDefault() ?? Environment.GetEnvironmentVariable("User");
string connectionString = new NpgsqlConnectionStringBuilder
{
Host = "postgre16sep.postgres.database.azure.com",
Port = 5432,
Database = "postgres",
Username = User,
SslMode = SslMode.Require,
}.ToString();
NpgsqlDataSourceBuilder dataSourceBuilder = new (connectionString);
TimeSpan successRefreshInterval = TimeSpan.FromMinutes(55);
TimeSpan failureRefreshInterval = TimeSpan.FromSeconds(30);
dataSourceBuilder.UsePeriodicPasswordProvider(async (_, ct)
=> await GetAccessTokenAsync(ct), successRefreshInterval, failureRefreshInterval);
await using var dataSource = dataSourceBuilder.Build();
try
{
await dataSource.OpenConnectionAsync(cancellationToken);
}
catch (Exception e)
{
_logger.LogError(2004, e, "FAILED TO OPEN DATABASE CONNECTION");
return new BadRequestObjectResult(e.Message);
}
_logger.LogInformation(3011, "Connection opened successfully");
return new OkObjectResult("Connection opened successfully");
}
private async Task<string> GetAccessTokenAsync(CancellationToken cancellationToken)
{
var credential = new DefaultAzureCredential();
string resource = "https://ossrdbms-aad.database.windows.net";
TokenRequestContext tokenRequestContext = new TokenRequestContext( new[] {$"{resource}/.default" });
AccessToken fullToken = await credential.GetTokenAsync(tokenRequestContext, cancellationToken).ConfigureAwait(false);
return fullToken.Token;
}
}
}
OUTPUT
: