Azure SQL登录失败:VS凭证C#连接报错,SSMS带MFA可登录
我是已加入Azure Active Directory(AAD)的用户,尝试通过.NET C#使用Visual Studio凭证登录Azure SQL数据库时遇到错误:Login failed for user '<token-identified principal>'。不过我可以通过带有Azure MFA的SSMS正常登录该数据库。
public async Task<SqlConnection> GetAzureSqlAccessTokenAsync( AzureSqlConnectionOptions azureSqlConnectionOptions, CancellationToken cancellationToken = default) { var connectionStringBuilder = GetConnectionString(azureSqlConnectionOptions); var sqlConnection = new SqlConnection(connectionStringBuilder.ConnectionString); var tokenRequestContext = new TokenRequestContext(_azureSqlScopes); var chainedTokenCredential = new ChainedTokenCredential( //new ManagedIdentityCredential(), new VisualStudioCredential(), new VisualStudioCodeCredential(), new AzureCliCredential() ); var token = await chainedTokenCredential.GetTokenAsync(tokenRequestContext, cancellationToken); sqlConnection.AccessToken = token; try { // sanity test await sqlConnection.OpenAsync(); // fails here var sqlCommand = new SqlCommand("SELECT GETDATE()", sqlConnection); var currentTime = await sqlCommand.ExecuteScalarAsync(cancellationToken); } catch(Exception e) { var ex = e.InnerException; } return sqlConnection; }
检查Azure SQL权限配置:确保你的AAD账户在Azure SQL数据库中被授予正确登录权限,且已在目标数据库创建对应用户。可通过以下T-SQL确认:
SELECT name FROM sys.database_principals WHERE type_desc = 'EXTERNAL_USER';若未找到你的账户,需先在服务器级别创建登录,再在数据库级别创建用户并授权:
-- 服务器级别创建AAD登录 CREATE LOGIN [你的AAD账户邮箱] FROM EXTERNAL PROVIDER; -- 切换到目标数据库,创建用户并授予权限 USE [你的数据库名]; CREATE USER [你的AAD账户邮箱] FROM LOGIN [你的AAD账户邮箱]; ALTER ROLE db_datareader ADD MEMBER [你的AAD账户邮箱]; ALTER ROLE db_datawriter ADD MEMBER [你的AAD账户邮箱];验证Token请求的Scope:确保
_azureSqlScopes使用正确的Azure SQL资源范围,正确值应为https://database.windows.net/.default。Scope错误会导致获取的Token无访问Azure SQL的权限。确认Visual Studio登录账户一致性:检查Visual Studio当前登录的AAD账户是否与SSMS登录的一致,可通过
工具>选项>Azure服务身份验证查看或切换账户。排查Token有效性:获取Token后,用JWT解析工具查看内容,确认
upn/name为你的AAD账户,且aud(受众)为https://database.windows.net/。排除多凭证干扰:暂时移除ChainedTokenCredential中的其他凭证,仅保留VisualStudioCredential测试:
var credential = new VisualStudioCredential(); var token = await credential.GetTokenAsync(tokenRequestContext, cancellationToken);
内容的提问来源于stack exchange,提问作者Gauravsa

