我们已通过 Azure AD(实现 OAuth 2.0)对多租户 SaaS 应用程序实施身份验证。 API 可通过 Angular SPA 访问,也可由其他客户端(例如具有专用客户端 ID 的注册 REST 客户端)访问。如果相关:我们使用授权代码流程。
在同一个应用程序上,我们有一个 OData API,我们希望通过它提供对用户应用程序(例如 Excel)的数据访问。由于我们是一个多租户应用程序,因此需要像访问“普通”Web API 时一样对连接进行身份验证,以便我们的数据层可以过滤该租户拥有的数据。
尽管我们只使用 Microsoft 服务(通过 Azure),但 Microsoft Excel 如何使用正确的身份验证方法连接到 OData 源似乎并不明显。我发现一篇文章解释了如何使用具有自定义连接定义的 Power Query 编辑器。我不会考虑这种方法,因为它对于典型的最终用户来说不是一个强大的解决方案。除了这种自定义配置方法之外,我还阅读了有关接管连接的商业第三方库的信息。然而,对于我的 SaaS 客户,我不能建议将此作为通用解决方案。
我还发现了另一篇文章,它使用 Azure 函数作为代理 API 来获取数据。对于最终用户来说,这似乎是一个强大的解决方案,但我不确定如何安全、正确地为正确的用户验证 API(本文中的示例专用于 1 个租户)。
问: 是否有强大的(开箱即用的)配置供最终用户从 Excel 访问经过 OAuth 验证的 OData feed/API?如果没有,我应该考虑哪些安全的替代方案?
您可以从客户端应用程序(例如 Excel、Word、Powerpoint 和 Publisher)在 AzureAD 上进行 OAuth 2.0 身份验证。这适用于打开整个文件(Office 2016 或更高版本)或从网页导入数据(Office 2019 / M365 应用程序)。
在 REST 客户端中使用 OAuth 身份验证时,设置 OAuth 身份验证的方式与常规且记录良好的 OAuth 流程略有不同。
而不是发送将客户端转发到 https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize 的标头 您需要返回http响应代码401(未经授权)并添加下一个标头:
WWW-Authenticate: Bearer resource="https://management.azure.com/" client_id="{the client id of your registered app in Azure AD}", trusted_issuers="00000001-0000-0000-c000-000000000000@*", token_types="app_asserted_user_v1 service_asserted_app_v1", authorization_uri="https://login.microsoftonline.com/{tenant}/oauth2/v2.0/authorize",Basic Realm=""'
在 Azure AD 中您的应用程序注册中:
注意:所有这些都没有记录在案。我通过嗅探 Outlook 和 O365 之间的流量发现了标头。
顺便说一句:如果您使用 webdav 协议提供文件:从网页中打开 Excel 文件可以很好地使用 javascript:
location.href = "ms-excel:ofe|https://{yourAPI}/your_output.xlsx"
答案已编辑为最终工作版本
部分感谢其他人对此线程的评论,我已经能够使其正常工作。这是我的最终解决方案(根据原始答案编辑,缺少一些拼图)
我在 Azure 中注册了应用程序,公开了 API,将应用程序 ID URI 更改为我验证的应用程序 url 并添加了 user_impersonation 范围。
您需要确保您在 Azure AD 中拥有经过验证的自定义域名。
我创建了一个.net 6 WebApi项目,制作了一个简单的odata控制器。
[Route("odata")]
public class WBSController : BaseODataController
{
public WBSController(IDbContextFactory<TableDbContext> db) : base(db)
{
}
[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[EnableQuery]
[HttpGet("WBS")]
public IQueryable<WBS> Get()
{
IQueryable<WBS> ret = Db.WBS;
return ret;
}
}
然后我在 Program.cs 中配置了 API。 (注意:对于客户端 ID - 使用您的应用程序 ID Uri。
程序.cs
.AddMicrosoftIdentityWebApi(
opt => //JwtBearerOptions
{
opt.Audience = "[Your App Id Uri eg. acme.com.au]";
opt.Events = new JwtBearerEvents()
{
OnChallenge = async ctxv =>
{
opt.Challenge =
@"Bearer realm="""", client_id=""[Your App Id Uri]"", trusted_issuers=""00000001-0000-0000-c000-000000000000@*"", token_types=""app_asserted_user_v1 service_asserted_app_v1"", authorization_uri=""https://login.microsoftonline.com/[Your Tenant Id]/oauth2/v2.0/authorize"""; //This is the magic that forces the Microsoft login dialog to open
}
};
},
opt => //MicrosoftIdentityOptions
{
opt.Instance = "https://login.microsoftonline.com/";
opt.ClientId = "[Your App Id Uri]";
opt.TenantId = "common";
},
$"{JwtBearerDefaults.AuthenticationScheme}" //Scheme Name
);
如果您遇到以下错误,则表示您尚未将 Azure AD 中的 App ID 设置为已验证的应用程序 url: invalid_resource:AADSTS500011: 在名为 .. 的租户中找不到资源主体 ...... ...
如果出现任何错误,或者没有执行任何操作,请使用 Fiddler 运行跟踪。这就是我确定它正在寻找 user_impersonation 范围的方式。
如果所有这些步骤都正确完成,您最终应该在 Excel 中得到一个可刷新的 OData 数据表。
我注意到微软表示不支持连接到这样的“任意”服务。 https://learn.microsoft.com/en-us/power-query/connectors/odatafeed#authenticating-to-任意-services。
但是我相信这是为 Excel 超级用户提供从 Web Api 访问结构化数据的能力的一个非常好的方法。我希望这篇文章可以为您节省我花在做这件事上的时间。
嗨@MotKohn 你是如何成功地与 localhos 合作的?
谢谢