Google apps script 如何将需要授权的独立Google应用脚本web应用嵌入到新的Google站点?

Google apps script 如何将需要授权的独立Google应用脚本web应用嵌入到新的Google站点?,google-apps-script,x-frame-options,google-sites-2016,Google Apps Script,X Frame Options,Google Sites 2016,我创建了一个独立的GoogleApps脚本web应用程序,我正试图将它嵌入到新的Google站点中。当我登录到用于创建应用程序脚本项目的帐户时,它可以正常工作。但是,如果我登录到另一个尚未授权web应用程序的帐户,则会加载Google站点页面,但带有嵌入式应用程序脚本项目的iFrame不会正确加载 相反,iFrame显示“accounts.google.com拒绝连接”,控制台显示“拒绝在帧中显示“”,因为它将“X-frame-Options”设置为“deny” 据我所知,新用户无权使用我的应用

我创建了一个独立的GoogleApps脚本web应用程序,我正试图将它嵌入到新的Google站点中。当我登录到用于创建应用程序脚本项目的帐户时,它可以正常工作。但是,如果我登录到另一个尚未授权web应用程序的帐户,则会加载Google站点页面,但带有嵌入式应用程序脚本项目的iFrame不会正确加载

相反,iFrame显示“accounts.google.com拒绝连接”,控制台显示“拒绝在帧中显示“”,因为它将“X-frame-Options”设置为“deny”

据我所知,新用户无权使用我的应用脚本Web App,这会触发授权流。但是,当授权流开始加载Google登录页面(?…从上面开始)时,它会中断,因为登录页面的X-Frame-Options标题设置为Deny

我确实尝试过HTMLoutput.setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL)(请参阅),但我很确定导致谷歌网站iFrame加载错误的问题不是我的应用程序,而是谷歌的登录页面

谷歌网站链接:

链接到应用程序脚本Web应用程序:

谷歌关于如何在新网站中嵌入应用程序脚本的文档:

如何授权新用户从Google站点访问我的web应用程序


我是否需要首先将他们引导到我发布的应用程序脚本站点,以通过授权流程,然后引导他们返回我的谷歌站点(显然这是一个糟糕的选择)?

首先,你的分析是正确的。谷歌的登录页面(事实上有很大一部分谷歌托管内容)的X-Frame-Options设置为deny,由于该设置,重定向被阻止在iframe中加载。如果用户已经登录到Google,但尚未授权该应用程序,我认为大多数情况下,他们应该在iframe中看到授权对话框流,而不会出现错误(Alan Wells所报告的)。但是,我没有完全测试,可能是对于同时登录多个(例如登录多个Gmail)的用户,它会将您踢出登录页面并触发X-Frame-Options块

不管怎样,经过一番挖掘,我找到了一个可行的解决办法。这有点麻烦,因为应用程序脚本对可以使用的东西有各种各样的限制。例如,我首先想使用
postMessage
将消息从嵌入的iframe传递到父页面,如果父页面在X秒内没有收到消息,它将假定iframe无法加载,并将重定向用户以登录/授权应用程序。唉,
postMessage
不能很好地使用应用程序脚本,因为它们双重嵌入了iFrame

解决: JSONP: 我找到的第一个解决方案是使用JSONP方法。谷歌简要地提到了这一点。首先,在iframe上放置一个覆盖,提示用户对应用进行身份验证,并提供一个这样做的链接。然后加载应用程序脚本两次,一次作为iframe,然后再次作为
标记。如果
标记成功加载,它将调用一个回调函数,该函数将隐藏提示覆盖,以便下面的iframe可见

这是我的代码,可以让您看到它是如何工作的:

添加的HTML:


.AppSwidgetRapper{
位置:固定;
}
.appsWidget{
宽度:100%;
身高:100%;
最小宽度:300px;
最小高度:300px;
边界:没有!重要;
}
罗格杜特先生{
顶部:0px;
左:0px;
位置:绝对位置;
宽度:100%;
身高:100%;
背景色:黑色;
文本对齐:居中;
}
您需要“授权”此小部件。
登录/授权
功能验证成功(电子邮件){
控制台日志(电子邮件);
//隐藏验证提示覆盖
document.querySelector('.loggedOut').style.display='none';
}
document.queryselectoral('.authButton').forEach(函数(elem){
元素addEventListener('click',函数(evt){
var currentUrl=document.location.href;
var authPage='1〕https://script.google.com/macros/s/SCRIPT_ID/exec?auth=true&redirect='+encodeURIComponent(当前URL);
窗口。打开(authPage,“U blank”);
});
});
和Code.gs(应用程序脚本)

函数doGet(e){
var email=Session.getActiveUser().getEmail();
if(e.parameter中的e.queryString&&jsonpCallback){
//JSONP回调
//获取回调函数的字符串名称
var cbFnName=e.parameter['jsonpCallback'];
//准备字符串化的JS,当从标记调用时将对其进行计算
var scriptText=“window.+cbFnName+”(“+email+”);”;
//为JS返回正确的MIME类型
返回ContentService.createTextOutput(scriptText).setMimeType(ContentService.MimeType.JAVASCRIPT);
}
else if(e.queryString&('auth'在e.parameter中| |'redirect'在e.parameter中)){
//已打开脚本以便在新选项卡中进行身份验证
var rawHtml='您已成功授权小部件。现在可以关闭此选项卡并刷新以前所在的页面。

; if(e.参数中的“重定向”){ rawHtml+='
'; } 返回HtmlService.createHtmlOutput(rawHtml); } 否则{ //在iframe中显示HTML var rawHtml=“应用程序脚本已成功加载到iframe!” +“\n” +“用于授权的用户电子邮件:”; var template=HtmlService.createTemplate(rawHtml); template.authedEmail=电子邮件; 返回template.evaluate().setXFrameOptionsMode(HtmlService.XFrameOptionsMode.ALLOWALL); } }
在本例中,“authSuccess”是我的JSONP回调函数,应该通过授权使用的电子邮件调用该函数