如何通过MSAL及Microsoft.Data.SqlClient 5.0解决EF Core迁移Azure SQL登录失败问题
背景
我有一个基于EF Core迁移创建数据库的桌面应用(仓库地址:https://github.com/dgxhubbard/CoreAzureWpf),支持Postgres、Sql Server和Sqlite。现在计划改用带Azure AD认证的Azure SQL Instance存储数据库,已完成以下基础配置:
- 创建Azure订阅与Azure SQL Instance
- 在订阅中配置了拥有全局管理员权限、同时作为该SQL实例管理员的AD用户(服务器启用混合模式认证)
- 为WPF应用的三种数据库类型创建了迁移,且迁移在对应数据库上均可正常执行
- 引入MSAL库与数据库拦截器,当前使用
Microsoft.Data.SqlClient5.x版本
当前配置细节
- 桌面应用已在Azure AD中注册为多租户应用(也尝试过单租户模式)
- 通过「我的组织使用的API」添加了Azure SQL Database权限(未找到Azure SQL Server选项)
- 应用将
GtContext关联到AzureAdDbConnectorInterceptor拦截器,该拦截器通过AzureAdCredentials获取有效访问令牌,并设置到Microsoft.Data.SqlClient.SqlConnection的AccessToken属性中
遇到的问题
输入Azure SQL实例地址与数据库名称后,拦截器能成功获取并设置有效访问令牌,但调用Migrate()方法后出现大量SQL异常,最终触发**「Login failed for user ''」**错误。
应用运行模式
应用支持四种数据库连接模式:
- 带Azure AD的Azure SQL Instance:输入实例地址(格式如
xxx.database.windows.net)、数据库名称后创建 - 带管理员账号的Azure SQL Instance:输入实例地址、管理员账号密码、数据库名称后创建
- 带集成安全的本地Sql Server:输入服务器名称、数据库名称(无需账号密码)后创建
- 无集成安全的本地Sql Server:输入服务器名称、账号密码、数据库名称后创建
需求
解决上述认证失败问题,实现通过Azure AD认证,使用EF Core迁移创建Azure SQL数据库。
1. 修正Azure AD应用权限配置
Azure SQL Database的权限是正确的(没有Azure SQL Server选项属于正常情况,Azure SQL的API权限统一归类为Azure SQL Database),但需确保配置的是应用权限而非委派权限,同时完成管理员同意:
- 在Azure AD应用的「API权限」中,添加Azure SQL Database的
user_impersonation应用权限 - 点击「授予管理员同意」完成权限生效
2. 规范连接字符串
连接字符串需移除User ID、Password等传统认证参数,添加Authentication=Active Directory Access Token标识,示例:
Server=tcp:{你的实例地址}.database.windows.net,1433;Database={你的数据库名};Authentication=Active Directory Access Token;
3. 确保拦截器在每次连接打开前设置令牌
EF Core迁移过程中可能多次创建新连接,需在每次连接打开前注入令牌,修改拦截器的ConnectionOpeningAsync方法:
public override async ValueTask<InterceptionResult> ConnectionOpeningAsync(DbConnection connection, ConnectionEventData eventData, InterceptionResult result, CancellationToken cancellationToken = default) { if (connection is SqlConnection sqlConnection && string.IsNullOrEmpty(sqlConnection.AccessToken)) { var token = await AzureAdCredentials.GetAccessTokenAsync(); sqlConnection.AccessToken = token; } return await base.ConnectionOpeningAsync(connection, eventData, result, cancellationToken); }
4. 确认AD用户的数据库创建权限
即使AD用户是SQL实例管理员,也需明确赋予其创建数据库的权限:
使用SQL认证登录Azure SQL Instance,执行以下SQL语句:
ALTER SERVER ROLE dbcreator ADD MEMBER [你的AD用户账号@域名.com];
5. 检查MSAL令牌请求范围
获取令牌时,需使用Azure SQL的默认范围https://database.windows.net/.default,示例代码:
var scopes = new[] { "https://database.windows.net/.default" }; var result = await _app.AcquireTokenInteractive(scopes).ExecuteAsync();
6. 验证令牌有效性
使用JWT解析工具检查获取到的令牌:
- 确认
aud(受众)字段值为https://database.windows.net/ - 确认
roles或scp字段包含对应权限
7. 迁移执行场景适配
如果是在WPF应用内调用Migrate(),确保MSAL的交互式登录窗口能正常弹出并完成认证;如果是命令行环境执行迁移,需切换为设备码流等非交互式认证方式。
内容的提问来源于stack exchange,提问作者dgxhubbard

