使用托管标识Object Id而非UserId连接Azure PostgreSQL
问题描述
我需要一种简洁方式,通过托管标识连接Azure PostgreSQL数据库,同时兼容以下场景:
- 部署后的应用(Azure Web API、Azure VM)
- Visual Studio本地开发
目前已实现本地和部署环境获取有效访问令牌并连接数据库,但存在以下问题:
- 部署环境中无法从访问令牌自动提取连接字符串所需的
UserId值(本地可通过upnclaim获取,但云端托管标识的令牌无此claim) - 疑惑为何使用访问令牌时仍需
UserId——令牌中包含oid(ObjectId),且数据库通过pgaadauth_list_principals(false)可查看到用户名与ObjectId的关联,是否能用ObjectId替代UserId连接? - 希望避免将
UserId存入环境变量/配置文件,优先从访问令牌自动获取所需信息。
解决方案
核心原理说明
Azure PostgreSQL的AAD认证要求UserId必须与数据库中预先创建的AAD主体用户名完全匹配:
- 该用户名可以是AAD用户的UPN(本地开发场景)、托管标识的名称或客户端ID(部署场景)
- 令牌中的
oid是Azure AD层面的对象ID,PostgreSQL无法直接通过它映射到数据库用户,因此不能直接用oid作为UserId。
适配多场景的UserId提取方案
根据不同环境的令牌claim差异,从令牌中提取对应的值作为UserId,前提是数据库中创建的AAD主体用户名与提取值一致:
代码实现
// 获取访问令牌(兼容本地VS和Azure托管标识) var credential = new DefaultAzureCredential(); var accessToken = credential.GetToken( new TokenRequestContext(new[] { "https://ossrdbms-aad.database.windows.net/.default" }), CancellationToken.None); // 解析JWT令牌 var handler = new JwtSecurityTokenHandler(); var jsonToken = handler.ReadJwtToken(accessToken.Token); // 适配不同场景提取UserId string userId; // 本地VS开发:用UPN(对应数据库中创建的AAD用户) var upnClaim = jsonToken.Claims.FirstOrDefault(c => c.Type == "upn"); // 托管标识场景1:用主体名称(对应数据库中按名称创建的托管标识用户) var nameClaim = jsonToken.Claims.FirstOrDefault(c => c.Type == "name"); // 托管标识场景2:用客户端ID(对应数据库中按Client ID创建的托管标识用户) var clientIdClaim = jsonToken.Claims.FirstOrDefault(c => c.Type == "client_id"); if (upnClaim != null) { userId = upnClaim.Value; } else if (nameClaim != null) { userId = nameClaim.Value; } else if (clientIdClaim != null) { userId = clientIdClaim.Value; } else { throw new InvalidOperationException("无法从访问令牌中获取有效的用户ID"); } // 构建连接字符串 var host = "<server-name>.postgres.database.azure.com"; var database = "<database-name>"; var connectionString = $"Host={host};" + $"Database={database};" + $"User Id={userId};" + $"Password={accessToken.Token};" + $"SSL Mode=Require;" + $"Trust Server Certificate=true"; // 建立数据库连接 using var pgSqlConnection = new NpgsqlConnection(connectionString); pgSqlConnection.Open();
数据库用户创建示例
根据你选择的UserId类型,在Azure PostgreSQL中创建对应的AAD主体用户:
- 本地AAD用户(UPN):
CREATE USER "your-email@domain.com" WITH LOGIN PASSWORD 'dummy' ROLE azure_ad_user;
- 托管标识(名称):
CREATE USER "your-managed-identity-name" WITH LOGIN PASSWORD 'dummy' ROLE azure_ad_user;
- 托管标识(客户端ID):
CREATE USER '12345678-1234-1234-1234-1234567890ab' WITH LOGIN PASSWORD 'dummy' ROLE azure_ad_user;
注:
Password为占位符,AAD认证时不会使用,但PostgreSQL语法要求必须指定。
内容的提问来源于stack exchange,提问作者Stanton
相关产品推荐
相关产品推荐

