为 SharePoint 中的跨域库创建自定义代理页

在构建 SharePoint 外接程序时,您通常必须包含来自各个源的数据。 然而,出于安全考虑,阻止机制会阻止同时与多个域通信。

如果您提供在远程外接程序基础结构中托管的自定义代理页,可以使用跨域库访问远程外接程序中的数据。 作为开发人员,您负责实施自定义代理页,并且必须处理自定义逻辑,例如远程外接程序的身份验证机制。 如果您希望在客户端级别发生通信,请结合使用跨域库和自定义代理页。

使用本文中的示例的先决条件

需要一个如开始创建提供程序托管的 SharePoint 加载项中所述的开发环境。

将自定义代理页用于 SharePoint 加载项前要了解的核心概念

下表列出了一些有用的文章,可帮助你了解 SharePoint 加载项中的跨域方案所涉及的概念。

文章标题 说明
SharePoint 外接程序 了解 SharePoint 中新的外接程序模型,可以利用此模型来创建对最终用户来说是小型且易于使用的解决方案的外接程序。
SharePoint 外接程序的安全数据访问和客户端对象模型 了解 SharePoint 外接程序中的数据访问选项。本主题提供有关您在外接程序中使用数据时必须从中选择的高级别替代方案的指导。
SharePoint 中的主机 Web、外接程序 Web 和 SharePoint 组件 了解主机 Web 和外接程序 Web 之间的区别。 了解 SharePoint 外接程序中可以包括哪些 SharePoint 组件、将哪些组件部署到主机 Web、将哪些组件部署到外接程序 Web 以及如何将外接程序 Web 部署到隔离域中。
客户端跨域安全性 了解跨域威胁和用例以及跨原始请求的安全原则,并权衡开发人员增强从在浏览器中运行的 Web 应用程序的跨域访问的风险。

代码示例:使用跨域库的自定义代理页访问远程数据

若要从远程服务中读取数据,必须执行以下操作:

  1. 创建 SharePoint 外接程序项目。

  2. 修改外接程序清单以允许来自远程外接程序的通信。

  3. 在 Web 项目中创建自定义代理页和内容页。

  4. 创建一个使用 SharePoint 外接程序项目中的跨域库的网页。

创建 SharePoint 加载项项目

  1. 以管理员身份打开 Visual Studio。 (为此,请右键单击“开始”菜单上的“Visual Studio”图标,然后选择“以管理员身份运行”。)

  2. 按照开始创建提供程序托管的 SharePoint 加载项中的说明,创建提供程序托管的 SharePoint 加载项,并将其命名为 ProxyPageApp

编辑加载项清单文件

  1. 在“解决方案资源管理器”中,右键单击 AppManifest.xml 文件,然后选择“查看代码”

  2. 将整个 AppPrincipal 元素替换为以下内容。

    <AppPrincipal>
        <Internal AllowedRemoteHostUrl="~remoteAppUrl"/>
    </AppPrincipal>
    

注意

AllowedRemoteHostUrl 属性用于指定远程域。 ~remoteAppUrl 解析为远程加载项 URL。 有关令牌的详细信息,请参阅了解 SharePoint 加载项的应用部件清单 (manifest) 结构和包

创建自定义代理页

  1. 创建 Visual Studio 解决方案后,右键单击 Web 应用程序项目(而不是 SharePoint 加载项项目),并添加一个新的 Web 表单,方法是选择“添加”>“新项目”>“Web”>“Web 表单”。 将表单命名为 Proxy.aspx

  2. 在 Proxy.aspx 文件中,将整个 HTML 元素及其子项替换为以下 HTML 代码。 保留 HTML 元素上的所有标记不变。 HTML 代码包含标记和执行以下任务的 JavaScript:

    • 为跨域库 JavaScript 文件提供一个占位符。

    • 从引用网站提取外接程序 Web URL。

    • 将跨域库 JavaScript 文件动态加载到此占位符中。

    • 提供 RequestExecutorMessageProcessor 对象的设置。

    • 初始化 RequestExecutorMessageProcessor 对象。

    <html xmlns="http://www.w3.org/1999/xhtml">
    <head runat="server">
        <meta http-equiv="X-UA-Compatible" content="IE=8" /> 
        <title>Custom Proxy Host Page</title>
        <script 
            src="http://ajax.aspnetcdn.com/ajax/4.0/1/MicrosoftAjax.js" 
            type="text/javascript">
        </script>
        <script 
            type="text/javascript" 
            src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.7.2.min.js">
        </script>
    
        <!-- Script to load the cross-domain library js file -->
        <script type="text/javascript">
            var hostweburl;
    
            $(document).ready(function(){
                //Get the URI decoded host web URL.
                hostweburl =
                    decodeURIComponent(
                        getQueryStringParameter("SPHostUrl")
                );
    
                // The cross-domain js file is in a URL in the form:
                // host_web_url/_layouts/15/SP.RequestExecutor.js
                var scriptbase = hostweburl + "/_layouts/15/";
    
                // Load the js file 
                $.getScript(scriptbase + "SP.RequestExecutor.js", initCustomProxy);
            });
    
            //Function to initialize the custom proxy page
            //  must set the appropriate settings and implement
            //  proper authentication mechanism
            function initCustomProxy() {
                var settings =
                {
                    originAuthorityValidator: function (messageOriginAuthority) {
                        // This page must implement the authentication for the
                        //   remote add-in.
                        // You should validate if messageOriginAuthority is
                        //  an approved domain to receive calls from.
                        return true;
                    }
                };
                SP.RequestExecutorMessageProcessor.init(settings);
            }
    
            // Function to retrieve a query string value.
            // For production purposes you may want to use
            //  a library to handle the query string.
            function getQueryStringParameter(paramToRetrieve) {
                var params =
                    document.URL.split("?")[1].split("&amp;");
                var strParams = "";
                for (var i = 0; i < params.length; i = i + 1) {
                    var singleParam = params[i].split("=");
                    if (singleParam[0] == paramToRetrieve)
                        return singleParam[1];
                }
            }
        </script>
    </head>
    <body>
    
    </body>
    </html>
    

重要

在生产 SharePoint 加载项中,必须在设置中提供授权逻辑并返回 originAuthorityValidator 对象中的适当值。

创建内容页

  1. 右键单击解决方案资源管理器中的 Web 应用程序项目,然后通过选择“添加新>> Web Web 窗体”来添加新的 Web>窗体。 将窗体命名 为 Content.aspx

  2. 将以下代码复制并粘贴到代码隐藏文件中的 Page_Load 方法。 该代码执行以下任务:

    • 将输出 content-type 设置为 text/plain

    • 将此内容写入输出缓冲区。

    • 结束连接。

    string content;
    content = "Just some text.";
    Response.ContentType="text/plain";
    Response.Write(content);
    Response.End();
    
    

创建使用跨域库的 SharePoint 网页

  1. 右键单击 SharePoint 加载项项目,然后选择“添加”>“新项目”>“Office/SharePoint”>“模块”

  2. 将该模块命名为 Pages,然后选择“添加”

  3. 右键单击“Pages”文件夹,然后选择“添加”>“新项目”>“Office/SharePoint”>“页面”

  4. 将该页面命名为 Home.aspx,然后选择“添加”

  5. 打开“Home.aspx”页(如果没有自动打开)。

  6. 将以下代码复制并粘贴到 PlaceHolderMain 内容标记中。

    <!-- The page dynamically loads the cross-domain library's
        js file, rescript acts as the placeholder. -->
    <script 
        type="text/javascript"
        id="rescript"
        src="../_layouts/15/SP.RequestExecutor.js">
    </script>
        Data from the remote domain: <span id="TextData"></span>
    
        <!-- Main script to retrieve the host web's title -->
        <script type="text/javascript">
        (function () {
            var executor;
            var hostweburl;
            var remotedomain;
    
            remotedomain = "<your_remote_add-in_domain>";
    
            //Get the URI decoded host web URL.
            hostweburl =
                decodeURIComponent(
                    getQueryStringParameter("SPHostUrl")
            );
    
            // Initialize the RequestExecutor with the custom proxy URL.
            executor = new SP.RequestExecutor(remotedomain);
            executor.iFrameSourceUrl = "Proxy.aspx?SPHostUrl=" + hostweburl;
    
            // Issue the call against the remote endpoint.
            // The response formats the data in plain text.
            // The functions successHandler and errorHandler attend the
            //      sucess and error events respectively.
            executor.executeAsync(
                {
                    url:
                        remotedomain + "Content.aspx",
                    method: "GET",
                    headers: { "Accept": "text/plain" },
                    success: successHandler,
                    error: errorHandler
                }
            );
        })();
    
        // Function to handle the success event.
        // Prints the data to the placeholder.
        function successHandler(data) {
            document.getElementById("TextData").innerText =
                data.body;
        }
    
        // Function to handle the error event.
        // Prints the error message to the page.
        function errorHandler(data, errorCode, errorMessage) {
            document.getElementById("TextData").innerText =
                "Could not complete cross-domain call: " + errorMessage;
        }
    
        // Function to retrieve a query string value.
        // For production purposes you may want to use
        //  a library to handle the query string.
        function getQueryStringParameter(paramToRetrieve) {
            var params =
                document.URL.split("?")[1].split("&amp;");
            var strParams = "";
            for (var i = 0; i < params.length; i = i + 1) {
                var singleParam = params[i].split("=");
                if (singleParam[0] == paramToRetrieve)
                    return singleParam[1];
            }
        }
        </script>
    
    

  7. 在前面粘贴的代码中,找到行 remotedomain = "<your_remote_add-in_domain>";,并将占位符 <your_remote_add-in_domain> 替换为 Web 应用程序在 Visual Studio 中使用 F5 运行外接程序时使用的“localhost”URL。 要查找此值,请在“解决方案资源管理器”中选择 Web 应用程序项目。 URL 属性位于“属性”窗格中。 使用整个值,包括协议、端口和右斜杠;例如 http://localhost:45072

  8. 保存并关闭文件。

  9. 打开 appmanifest.xml 文件,将"起始页"值设置为"ProxyPageApp/Pages/Home.aspx"。

生成并运行解决方案

  1. 确保已将 SharePoint 加载项项目设置为启动项目。

  2. 按 F5 键。

    注意

    按 F5 键时,Visual Studio 会生成解决方案并部署加载项,同时还会打开加载项的权限页面。

  3. 选择“信任它”按钮。

    此时会打开“主页”,其外观应如下所示。 可能需要几秒钟时间才会显示“Just some text”短语,因为它将从远程域的 Content.aspx 页面获取。

    具有来自远程服务的数据的 SharePoint 页面

解决方案疑难解答

问题 解决方案
在按 F5 键后,Visual Studio 不打开浏览器。 将 SharePoint 加载项项目设置为启动项目。
发生未处理异常“SP 未定义” 确保可在浏览器窗口中访问 SP.RequestExecutor.js 文件。

另请参阅