如何解决Azure SQL 通过 API 与 MS Identity Platform 以用户身份进行身份验证
我有一个调用 ASP.NET Core 3.1 Web API 的 ASP.NET Core 3.1 Web 应用程序,它依次访问 Azure SQL 数据库。身份验证通过 MSAL(Microsoft 身份平台)提供 - 即使用相对较新的 Microsoft.Identity.Web
和 Microsoft.Identity.Web.UI
库。
目标是确保用户在他/她自己登录的上下文中通过 API 从 SQL 中提取数据,从而实现行级安全、访问审计和其他好处。
我已成功使登录过程适用于 Web 应用程序 - 并通过它获取有效的访问令牌以使用我在向 AD 注册后者时创建的范围访问 API。
当我从 Visual Studio 在本地运行 API 和应用程序时,一切都按预期工作 - 向应用程序提供了正确的访问令牌以访问 API,并提供 API 以访问 SQL - 在这两种情况下,在用户(即我的)身份。
但是,当我将 API 发布到 Azure 上的应用服务并从本地版本的 Web 应用或应用服务托管版本访问它时,API 用于访问 SQL 的访问令牌包含API 的应用程序身份(系统分配的托管身份),而不是用户的身份。虽然我可以作为应用程序访问SQL,但这不是我们需要的。
Web 应用程序使用 GetAccessTokenForUserAsync
的 ITokenAcquisition
方法获取其访问令牌 - 将我为 API 定义的单一范围作为参数。
API 像这样获取它的令牌(以访问 SQL):
var token = await new AzureServiceTokenProvider().GetAccessTokenAsync("https://database.windows.net",_tenantId)
...其中 _tenantId 是订阅的租户 ID。
我已向 API 的 AD 注册添加了 SQL Azure 数据库“user_impersonation”API 权限 - 但这并没有帮助。顺便说一句,出于某种原因,Azure 将此权限的全名为 https://sql.azuresynapse.usgovcloudapi.net/user_impersonation
- 这有点令人担忧,因为这只是一个位于英国的常规 Azure 帐户。
我发现了一些与此类似的帖子,但主要是针对旧版本的解决方案集。我希望避免必须编写自己的代码来发布令牌请求 - 这应该由 MSAL 库处理。
我应该在登录后以某种方式分别从 Web 应用程序请求 SQL 访问范围,还是 API 应该做一些不同的事情来获取标识用户的 SQL 访问令牌?为什么在本地运行时能完美运行?
这似乎应该是一个非常常见的用例(最常见的?)但几乎没有记录 - 我发现的大多数文档仅涉及正在使用的应用程序标识,或者没有告诉您要做什么这个特殊的技术栈。
解决方法
最后——成功!最后,这是文档的关键部分:Microsoft identity platform and OAuth 2.0 On-Behalf-Of flow - 关键点是:
- 该应用仅需要令牌才能访问 API。
- 然后,API 代表通过第一个令牌标识的用户请求令牌以访问 SQL。
关键在于 - 由于 API 无法触发第二步的同意窗口 - 我必须使用 Azure 门户中的企业应用程序选项卡来预授予 SQL 权限。
所以好消息是它确实有效:也许对某些人来说很明显,但 IMO 花了太长时间才找到答案。我会在适当的时候写一篇关于如何做到这一点的更全面的解释,因为这不仅仅是我在努力解决这个问题。
坏消息是 - 在我的调查过程中 - 我发现 Azure B2C(这是我接下来需要添加的内容)不支持这种“代表”流程 - click here for details .这是一个巨大的耻辱,因为我认为这是它最明显的用例!哦,好吧,回到绘图板。
,我目前正在使用 Net5.0 Web 应用解决类似问题。它似乎在本地工作的原因是您使用可以访问 Azure SQL 的用户登录到 Visual Studio,而这些是您在 Db 中获得的权限。 IDE 使用这些凭据代替托管服务标识,后者会在您将应用上传到 Azure 时使用。
如您所见,在应用注册中,您需要为 Azure SQL 数据库 user_impersonation 的应用授予权限。
在您的代码中,您需要从 https://database.windows.net//.default 请求令牌(注意 // 因为 v1 端点需要它)。通过引用 /.default,您是在请求您在应用注册门户中为该应用选择的所有权限。
在 Startup.cs 中,您需要使用所需范围的 EnableTokenAcquisitionToCallDownstreamApi。
services.AddMicrosoftIdentityWebAppAuthentication(Configuration)
.EnableTokenAcquisitionToCallDownstreamApi(new[]
{"https://database.windows.net//.default"})
// Adds the User and App InMemory Token Cache
.AddInMemoryTokenCaches();
services.AddAuthorization(options =>
{
// By default,all incoming requests will be authorized according to the
// default policy
options.FallbackPolicy = options.DefaultPolicy;
});
services.AddDbContext<MyDatabaseContext>(options =>
options.UseSqlServer(
Configuration.GetConnectionString("MyAzureConnection")));
// The database interface
services.AddScoped<ITodos,TodoData>();
services.AddRazorPages()
.AddRazorRuntimeCompilation()
.AddMvcOptions(o =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
o.Filters.Add(new AuthorizeFilter(policy));
})
.AddMicrosoftIdentityUI();
您还需要使用 [AuthorizeForScopes(Scopes = new string[]{"https://database.windows.net//.default"}]
装饰您的控制器并包含该控制器所需的范围。对于 Razor,它位于页面模型的顶部,并且需要引用“使用 Microsoft.Identity.Web;”
namespace ToDoApp.Pages.Todos
{
[AuthorizeForScopes(ScopeKeySection = "AzureSQL:BaseUrl")]
public class CreateModel : PageModel
我将 appsettings.json 中的一个部分用于范围并使用 ScopeKeySection
检索它:
"AzureSQL": {
"BaseUrl": "https://database.windows.net//.default","Scopes": "user_impersonation"
}
这向您展示了将其包含在 MVC、Razor 和 Blazor 的何处:
最后,您的 DbContext 需要一个令牌,您可以将其从客户端应用程序传递给它(也许......)。
这就是我目前的做法
public class MyDatabaseContext : DbContext
{
private readonly ITokenAcquisition _tokenAcquisition;
public MyDatabaseContext (ITokenAcquisition tokenAcquisition,DbContextOptions<MyDatabaseContext> options)
: base(options)
{
_tokenAcquisition = tokenAcquisition;
string[] scopes = new[]{"https://database.windows.net//.default"};
var result = _tokenAcquisition.GetAuthenticationResultForUserAsync(scopes)
.GetAwaiter()
.GetResult();
token = result.AccessToken;
var connection = (SqlConnection)Database.GetDbConnection();
connection.AccessToken = result.token;
}
这是一个有缺陷的解决方案。如果我重新启动应用程序并尝试再次访问它,我会收到错误 Microsoft.Identity.Web.MicrosoftIdentityWebChallengeUserException: IDW10502: An MsalUiRequiredException was thrown due to a challenge for the user
好像跟TokenCache有关。如果我退出并再次登录或清除浏览器缓存,错误将得到解决。我有一个解决方法可以在应用程序失败时登录,但由于我使用的是应用程序的凭据,因此存在不足。
但是,它以用户而不是具有用户权限的应用程序成功连接到 Azure SQL Db。当我解决错误(或找到错误)时,我会更新此答案。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。