我的 Office 加载项中的 Javascript 位于哪个域
On what domain is my Javascript in my Office Add-In
我们在 OWA 中有一个 Outlook 加载项运行。
- 清单位于 https://company.ourdomain.com
- Javascript 坐在 https://company.ourdomain.com
- 我们内部编写的自定义 Web 服务位于 https://company.ourdomain.com
当我从 JavaScript 中发出调用以响应加载项命令时,我在 ajax 调用中使用格式 https://company.ourdomain.com/api/Controller/Action。
我最终遇到了其中一个 CORS 错误(有时是飞行前错误,有时是 CORB)。如果 Javascript 实际上与 Web 服务位于同一域中,为什么我会收到此消息?
我假设我已经通过身份验证,因为我已经登录到我的 Outlook 帐户。
什么给了?
注意:
作为实验,我尝试通过直接输入 URL 来调用 RESTful(不涉及 OWA)。这导致代码针对 Azure AD 进行身份验证。然后我在同一个浏览器会话中登录到 OWA,一切正常。我是否真的需要在 Javascript 中进行身份验证,即使我调用的网络服务位于同一域中?
AJAX 产生错误的调用
请记住,在我通过直接从浏览器
调用我的 Web 服务来进行 RESTful 调用后,它会正常工作
var apiUri = '/api/People/ShowRecord';
$.ajax({
url: apiUri,
type: 'POST',
data: JSON.stringify(serviceRequest),
contentType: 'application/json; charset=utf-8',
dataType: 'json'
}).done(function (response) {
if (!response.isError) {
// response to successful call
}
else {
// ...
}
}).fail(function (status) {
// some other response
}).always(function () {
console.log("Completed");
});
观察
当我从地址栏调用 api 时,下面的代码是 运行。此代码永远不会被 Javascript
调用
[assembly: OwinStartup(typeof(EEWService.AuthStartup))]
namespace EEWService
{
public partial class AuthStartup
{
public void Configuration(IAppBuilder app)
{ app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
Notifications = new WsFederationAuthenticationNotifications
{
RedirectToIdentityProvider = (context) =>
{
context.ProtocolMessage.Whr = "ourdomain.com";
return Task.FromResult(0);
}
},
MetadataAddress = ConfigurationManager.AppSettings["ida:MetadataAddress"],
Wtrealm = ConfigurationManager.AppSettings["ida:Audience"],
TokenValidationParameters = new TokenValidationParameters
{
ValidAudiences = new string[] { $"spn:{ConfigurationManager.AppSettings["ida:Audience"]}" }
}
});
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
TokenValidationParameters = new TokenValidationParameters
{
ValidAudience = ConfigurationManager.AppSettings["ida:Audience"]
},
MetadataAddress = ConfigurationManager.AppSettings["ida:MetadataAddress"],
});
}
}
}
我认为这有一些问题。
第一个是您试图在提供代码的同一台服务器上提供静态内容。这通常被认为是一种不好的做法,纯粹是因为没有必要为静态内容浪费那些宝贵的服务器资源。理想情况下,您应该将静态内容上传到 CDN - 并让用户的浏览器向某些超级缓存文件服务器发出请求。但是 - 我知道您现在可能无法使用此选项。这也不是根本原因。
第二个也是真正的问题是,(你认为你是但是)你没有经过身份验证。 Outlook 网络插件中的身份验证默认情况下不会出现,这是您需要处理的事情。当 Outlook 将您的 Web 加载项加载到侧面板时,它会向您提供某些方法,您可以使用这些方法并创建一个伪身份(例如 Office.context.mailbox.userProfile.emailAddress
)——但如果您想要真正的身份验证,你需要自己做。
据我所知,有三种方法可以做到这一点。
- 第一个是通过Exchange Identity Token
- 第二个是通过Single Sign On feature
- 第三种——我认为实现起来最方便、逻辑最简单的是使用WebSockets。 (SignalR 可能是您所需要的)。
- 当用户加载您的第一个页面时,请确保像
window.Unique_ID
这样的 JS 值可供他们使用。这会派上用场的。
- 在您的 UI 中有一个按钮 - 上面写着 "Authenticate"
- 当用户单击此按钮时,您会将它们弹出到 url,这将重定向到您的身份验证 URL。 (类似于 https://company.ourdomain.com/redirToAuth)。这将避免您在侧面板中被阻止的麻烦,因为您正在使用
window.open
和您域中的 url。将 Unique_ID 传递给重定向,然后重定向到 OAuth 登录 URL。那应该看起来像 https://login.microsoftonline.com/......&state=Unique_ID
- 在弹出用户登录 window 之后,在你的主 JS(客户端)中,你打开一个到你的服务器的网络套接字,再次使用那个 Unique_ID 和开始听。
- 当用户完成身份验证时,OAuth 流程应该 post 返回访问令牌或代码。如果你得到了访问令牌,你可以通过套接字将它发送到前端(使用post-back参数中的Unique_ID)或者如果你有代码,你完成身份验证用户进行服务器到服务器调用,然后以相同的方式传递访问令牌。因此,您使用该唯一 ID 来跟踪用户连接的套接字,并将访问令牌中继到 仅 该用户。
我们在 OWA 中有一个 Outlook 加载项运行。
- 清单位于 https://company.ourdomain.com
- Javascript 坐在 https://company.ourdomain.com
- 我们内部编写的自定义 Web 服务位于 https://company.ourdomain.com
当我从 JavaScript 中发出调用以响应加载项命令时,我在 ajax 调用中使用格式 https://company.ourdomain.com/api/Controller/Action。
我最终遇到了其中一个 CORS 错误(有时是飞行前错误,有时是 CORB)。如果 Javascript 实际上与 Web 服务位于同一域中,为什么我会收到此消息?
我假设我已经通过身份验证,因为我已经登录到我的 Outlook 帐户。
什么给了?
注意: 作为实验,我尝试通过直接输入 URL 来调用 RESTful(不涉及 OWA)。这导致代码针对 Azure AD 进行身份验证。然后我在同一个浏览器会话中登录到 OWA,一切正常。我是否真的需要在 Javascript 中进行身份验证,即使我调用的网络服务位于同一域中?
AJAX 产生错误的调用 请记住,在我通过直接从浏览器
调用我的 Web 服务来进行 RESTful 调用后,它会正常工作 var apiUri = '/api/People/ShowRecord';
$.ajax({
url: apiUri,
type: 'POST',
data: JSON.stringify(serviceRequest),
contentType: 'application/json; charset=utf-8',
dataType: 'json'
}).done(function (response) {
if (!response.isError) {
// response to successful call
}
else {
// ...
}
}).fail(function (status) {
// some other response
}).always(function () {
console.log("Completed");
});
观察 当我从地址栏调用 api 时,下面的代码是 运行。此代码永远不会被 Javascript
调用[assembly: OwinStartup(typeof(EEWService.AuthStartup))]
namespace EEWService
{
public partial class AuthStartup
{
public void Configuration(IAppBuilder app)
{ app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
app.UseCookieAuthentication(new CookieAuthenticationOptions());
app.UseWsFederationAuthentication(
new WsFederationAuthenticationOptions
{
Notifications = new WsFederationAuthenticationNotifications
{
RedirectToIdentityProvider = (context) =>
{
context.ProtocolMessage.Whr = "ourdomain.com";
return Task.FromResult(0);
}
},
MetadataAddress = ConfigurationManager.AppSettings["ida:MetadataAddress"],
Wtrealm = ConfigurationManager.AppSettings["ida:Audience"],
TokenValidationParameters = new TokenValidationParameters
{
ValidAudiences = new string[] { $"spn:{ConfigurationManager.AppSettings["ida:Audience"]}" }
}
});
app.UseWindowsAzureActiveDirectoryBearerAuthentication(
new WindowsAzureActiveDirectoryBearerAuthenticationOptions
{
Tenant = ConfigurationManager.AppSettings["ida:Tenant"],
TokenValidationParameters = new TokenValidationParameters
{
ValidAudience = ConfigurationManager.AppSettings["ida:Audience"]
},
MetadataAddress = ConfigurationManager.AppSettings["ida:MetadataAddress"],
});
}
}
}
我认为这有一些问题。
第一个是您试图在提供代码的同一台服务器上提供静态内容。这通常被认为是一种不好的做法,纯粹是因为没有必要为静态内容浪费那些宝贵的服务器资源。理想情况下,您应该将静态内容上传到 CDN - 并让用户的浏览器向某些超级缓存文件服务器发出请求。但是 - 我知道您现在可能无法使用此选项。这也不是根本原因。
第二个也是真正的问题是,(你认为你是但是)你没有经过身份验证。 Outlook 网络插件中的身份验证默认情况下不会出现,这是您需要处理的事情。当 Outlook 将您的 Web 加载项加载到侧面板时,它会向您提供某些方法,您可以使用这些方法并创建一个伪身份(例如 Office.context.mailbox.userProfile.emailAddress
)——但如果您想要真正的身份验证,你需要自己做。
据我所知,有三种方法可以做到这一点。
- 第一个是通过Exchange Identity Token
- 第二个是通过Single Sign On feature
- 第三种——我认为实现起来最方便、逻辑最简单的是使用WebSockets。 (SignalR 可能是您所需要的)。
- 当用户加载您的第一个页面时,请确保像
window.Unique_ID
这样的 JS 值可供他们使用。这会派上用场的。 - 在您的 UI 中有一个按钮 - 上面写着 "Authenticate"
- 当用户单击此按钮时,您会将它们弹出到 url,这将重定向到您的身份验证 URL。 (类似于 https://company.ourdomain.com/redirToAuth)。这将避免您在侧面板中被阻止的麻烦,因为您正在使用
window.open
和您域中的 url。将 Unique_ID 传递给重定向,然后重定向到 OAuth 登录 URL。那应该看起来像https://login.microsoftonline.com/......&state=Unique_ID
- 在弹出用户登录 window 之后,在你的主 JS(客户端)中,你打开一个到你的服务器的网络套接字,再次使用那个 Unique_ID 和开始听。
- 当用户完成身份验证时,OAuth 流程应该 post 返回访问令牌或代码。如果你得到了访问令牌,你可以通过套接字将它发送到前端(使用post-back参数中的Unique_ID)或者如果你有代码,你完成身份验证用户进行服务器到服务器调用,然后以相同的方式传递访问令牌。因此,您使用该唯一 ID 来跟踪用户连接的套接字,并将访问令牌中继到 仅 该用户。
- 当用户加载您的第一个页面时,请确保像