使用Knex结合系统分配身份连接SQL Server时遇登录失败错误
Knex使用Azure系统分配身份连接SQL Server时出现空用户登录失败错误
我尝试用Knex结合Azure系统分配身份连接Microsoft SQL Server,已按要求配置认证方式,但始终收到如下错误:
ConnectionError: Login failed for user '' at ConnectionError (/node_modules/tedious/lib/errors.js:13:12) at Parser.<anonymous> (/node_modules/tedious/lib/connection.js:1194:51) at Parser.emit (node:events:517:28) at Readable.<anonymous> (/node_modules/tedious/lib/token/token-stream-parser.js:27:14) at Readable.emit (node:events:517:28) at addChunk (node/streams/readable:368:12) at readableAddChunk (node/streams/readable:341:9) at Readable.push (node/streams/readable:278:10) at next (node/streams/from:98:31) at process.processTicksAndRejections (node/process/task_queues:95:5)
环境与配置情况
- 使用Knex连接Microsoft SQL Server
- 已配置Knex采用Azure系统分配身份认证
- 运行环境(App Service/VM等)已启用并配置系统分配身份
- 确认配置参数无误,但仍出现空用户登录失败问题
我的连接配置代码:
dbConfig = { client: config.ENV.TNT_DB_CLIENT, connection: { server: config.ENV.TNT_DB_SERVER, authentication: { type: 'azure-active-directory-msi-app-service', options: { tenantId: config.ENV.AZURE_TENANT_ID } }, options: { database: config.ENV.TNT_DATABASE, trustServerCertificate: false, encrypt: true, requestTimeout: 300000 } }, plugins: [knexPlugin()], pool: { acquireTimeoutMillis: 300000, min: parseInt(config.ENV.TNT_DB_MIN_CONNECTION), max: parseInt(config.ENV.TNT_DB_MAX_CONNECTION) }, migrations: { tableName: 'knex_migrations' }, requestTimeout: 300000, connectionTimeout: 300000, acquireConnectionTimeout: 300000 };
可能的解决方向
1. 验证Knex与Tedious版本兼容性
Knex依赖tedious作为SQL Server驱动,部分旧版本tedious对Azure MSI身份认证的支持存在bug,无法正确获取MSI令牌,进而导致空用户登录失败。建议:
- 将tedious升级到最新稳定版(如>=16.0.0)
- 同步升级Knex到对应兼容版本
2. 检查MSI身份的数据库权限配置
确保系统分配的MSI身份已被正确授予SQL Server访问权限:
- 登录Azure Portal,进入目标SQL Server的「Azure Active Directory」选项卡
- 添加系统分配身份为SQL Server外部用户,并授予对应数据库角色(如
db_datareader/db_datawriter) - 执行SQL查询验证用户是否存在于目标数据库:
SELECT name FROM sys.database_principals WHERE name = N'<MSI身份名称>'
3. 匹配运行环境调整认证类型
如果运行环境不是App Service(如虚拟机、容器),需将认证类型改为azure-active-directory-msi-vm:
authentication: { type: 'azure-active-directory-msi-vm', // 非App Service环境使用该类型 options: { tenantId: config.ENV.AZURE_TENANT_ID } }
4. 清理重复的Timeout配置
当前配置中同时在connection.options和顶层重复设置了timeout参数,可能导致tedious内部逻辑冲突。建议将timeout参数统一放在connection.options中,移除顶层重复配置:
dbConfig = { client: config.ENV.TNT_DB_CLIENT, connection: { server: config.ENV.TNT_DB_SERVER, authentication: { type: 'azure-active-directory-msi-app-service', options: { tenantId: config.ENV.AZURE_TENANT_ID } }, options: { database: config.ENV.TNT_DATABASE, trustServerCertificate: false, encrypt: true, requestTimeout: 300000, connectionTimeout: 300000 } }, plugins: [knexPlugin()], pool: { acquireTimeoutMillis: 300000, min: parseInt(config.ENV.TNT_DB_MIN_CONNECTION), max: parseInt(config.ENV.TNT_DB_MAX_CONNECTION) }, migrations: { tableName: 'knex_migrations' } };
5. 手动验证MSI令牌获取
添加调试代码确认是否能正常获取MSI令牌,排查环境层面问题:
const { ManagedIdentityCredential } = require('@azure/identity'); async function getToken() { const credential = new ManagedIdentityCredential(); const token = await credential.getToken('https://database.windows.net/.default'); console.log('MSI Token:', token); } getToken().catch(console.error);
若无法获取令牌,需检查运行环境的MSI配置(如MSI_ENDPOINT、MSI_SECRET环境变量是否存在),或重新启用系统分配身份。
内容的提问来源于stack exchange,提问作者Sumit Patel
相关产品推荐
相关产品推荐

