使用Azure AD拦截器连接提示Login failed for user ''错误
你当前的拦截器仅重写了方法签名,没有实现AAD令牌注入的核心逻辑,连接发起时没有携带有效身份凭证,就会抛出Login failed for user ''错误。按以下步骤逐一排查修复即可:
- 补全拦截器的令牌注入逻辑
连接打开前需要主动获取Azure AD颁发给Azure SQL的访问令牌,赋值给SqlConnection.AccessToken属性,可直接使用以下可运行的实现:
using Azure.Core; using Azure.Identity; using Microsoft.Data.SqlClient; using Microsoft.EntityFrameworkCore.Diagnostics; using System.Data.Common; public class AadAuthenticationDbConnectionInterceptor : DbConnectionInterceptor { // Azure SQL的固定资源ID,不需要修改 private const string AzureSqlResourceScope = "https://database.windows.net/.default"; private static readonly TokenCredential Credential = new DefaultAzureCredential(); public override InterceptionResult ConnectionOpening( DbConnection connection, ConnectionEventData eventData, InterceptionResult result) { if (connection is SqlConnection sqlConnection && string.IsNullOrWhiteSpace(sqlConnection.AccessToken)) { var tokenRequest = new TokenRequestContext(new[] { AzureSqlResourceScope }); var accessToken = Credential.GetToken(tokenRequest, default); sqlConnection.AccessToken = accessToken.Token; } return base.ConnectionOpening(connection, eventData, result); } public override async ValueTask<InterceptionResult> ConnectionOpeningAsync( DbConnection connection, ConnectionEventData eventData, InterceptionResult result, CancellationToken cancellationToken = default) { if (connection is SqlConnection sqlConnection && string.IsNullOrWhiteSpace(sqlConnection.AccessToken)) { var tokenRequest = new TokenRequestContext(new[] { AzureSqlResourceScope }); var accessToken = await Credential.GetTokenAsync(tokenRequest, cancellationToken); sqlConnection.AccessToken = accessToken.Token; } return await base.ConnectionOpeningAsync(connection, eventData, result, cancellationToken); } }
注意实现里用到了Azure.Identity包,需要提前通过NuGet安装到项目中。
- 确认拦截器正确注入到EF Core管道
编写完拦截器后需要在DbContext配置时显式挂载,否则拦截器不会生效,注册示例:
// 在Program.cs/Startup.cs的服务配置段添加 services.AddDbContext<你的业务DbContext>(options => { options.UseSqlServer(配置中的连接字符串) .AddInterceptors(new AadAuthenticationDbConnectionInterceptor()); });
修正连接字符串配置
连接字符串中不能包含SQL认证相关的User ID、Password参数,也不要设置Trusted_Connection=True,这些配置会覆盖拦截器注入的AccessToken,正确格式参考:Server=tcp:你的Azure SQL实例名.database.windows.net,1433;Initial Catalog=目标数据库名;Encrypt=True;TrustServerCertificate=False;Connection Timeout=30;
如果你使用Microsoft.Data.SqlClient 3.0及以上版本,完全可以不用自定义拦截器,直接在连接字符串中添加Authentication=Active Directory Default,SDK会自动完成AAD身份认证流程,出错概率更低。校验本地开发环境的身份上下文
SSMS能正常连接不代表代码运行时能拿到正确的AAD身份:- 如果你用Visual Studio调试,进入「工具>选项>Azure服务认证」,确认当前选中的登录账号就是被授权访问Azure SQL的账号
- 如果你本地安装了Azure CLI,执行
az account show确认当前登录的租户、账号匹配预期,不匹配的话执行az login切换到对应账号 - 不要混淆Windows集成认证和AAD认证,SSMS登录时如果选择的是「Azure Active Directory - 通用MFA」,其登录上下文和SDK默认读取的本地身份上下文并不完全互通。
校验Azure SQL侧的权限配置
确认目标数据库中已经为对应AAD账号创建了映射并授予了必要权限,不要只把账号设为服务器级AAD管理员却忽略库级映射。在目标数据库下执行以下SQL检查账号是否存在:
SELECT name, type_desc FROM sys.database_principals WHERE type IN ('E','X');
如果结果中没有你的账号,执行以下语句创建并授权:
CREATE USER [你的账号完整邮箱@域名.com] FROM EXTERNAL PROVIDER; -- 按需授予对应角色权限,以下为常见的读写权限配置 ALTER ROLE db_datareader ADD MEMBER [你的账号完整邮箱@域名.com]; ALTER ROLE db_datawriter ADD MEMBER [你的账号完整邮箱@域名.com];
内容的提问来源于stack exchange,提问作者Ali Khan

