You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SharePoint 2016本地REST API跨域CORS与NTLM认证配置问题

SharePoint 2016 On-Premise跨域REST API访问:CORS与NTLM认证问题解决

环境

  • SharePoint版本:SharePoint 2016 On-Premise
  • IIS版本:Windows Server 2016 Standard 10.0.x
  • 认证方式:NTLM

涉及域名

  • 生产站点:https://shptest2.domain2.com
  • 类数据库站点:https://shpdatabase.domain3.com

目标

通过SharePoint REST API,从shptest2.domain2.com托管的Web应用访问shpdatabase.domain3.com上的列表。

当前shpdatabase.domain3.com服务器web.config配置

<configuration>
  <system.webServer>
    <httpProtocol>
      <customHeaders>
        <add name="X-Content-Type-Options" value="nosniff" />
        <add name="X-MS-InvokeApp" value="1; RequireReadOnly" />
        <add name="Access-Control-Allow-Headers" value="Origin, X-Requested-With, Content-Type, Accept" />
        <add name="Access-Control-Allow-Methods" value="POST,GET,OPTIONS,PUT,DELETE" />
        <add name="Access-Control-Allow-Credentials" value="true" />
      </customHeaders>
    </httpProtocol>
    <rewrite>
      <outboundRules>
        <clear />
        <rule name="AddCrossDomainHeader">
          <match serverVariable="RESPONSE_Access_Control_Allow_Origin" pattern=".*" />
          <conditions logicalGrouping="MatchAll" trackAllCaptures="true">
            <add input="{HTTP_ORIGIN}" pattern="^(https?://(.*\.)?domain1\.com|domain2\.com)$" />
          </conditions>
          <action type="Rewrite" value="{C:0}" />
        </rule>
      </outboundRules>
    </rewrite>
    <security>
      <requestFiltering allowDoubleEscaping="true">
        <fileExtensions>
          <clear />
        </fileExtensions>
        <hiddenSegments>
          <clear />
        </hiddenSegments>
        <requestLimits maxAllowedContentLength="2147483647" />
      </requestFiltering>
    </security>
    <validation validateIntegratedModeConfiguration="false" />
    <modules runAllManagedModulesForAllRequests="true">
      <!-- Module configuration here -->
    </modules>
    <handlers>
      <!-- Handler configuration here -->
    </handlers>
    <staticContent>
      <remove fileExtension=".dll" />
      <remove fileExtension=".exe" />
    </staticContent>
  </system.webServer>
</configuration>

测试JavaScript代码

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>SharePoint API Test</title>
    <script>
        async function getRemoteListItems() {
            const appWebUrl = 'https://shptest2.domain2.com';
            const hostWebUrl = 'https://shpdatabase.domain3.com';
            const url = `${appWebUrl}/_api/SP.AppContextSite(@target)/web/lists/getbytitle('test01')/items?$top=10&@target='${hostWebUrl}'`;

            try {
                const response = await fetch(url, {
                    method: 'GET',
                    headers: {
                        'Accept': 'application/json;odata=verbose'
                    },
                    credentials: 'include' // Allow sending cookies and NTLM authentication
                });

                if (!response.ok) {
                    throw new Error('Network response was not ok ' + response.statusText);
                }

                const data = await response.json();
                console.log(data);

                const contentDiv = document.getElementById('content');
                contentDiv.innerHTML = `<pre>${JSON.stringify(data, null, 2)}</pre>`;
            } catch (error) {
                console.error('There was a problem with the fetch operation:', error);
            }
        }

        document.addEventListener('DOMContentLoaded', (event) => {
            getRemoteListItems();
        });
    </script>
</head>
<body>
    <h1>SharePoint API Test</h1>
    <div id="content">
    </div>
</body>
</html>

遇到的问题

  • 使用credentials: 'same-origin'时,返回401 Unauthorized错误
  • 使用credentials: 'include'时,返回403 Forbidden错误

补充信息

  • IIS上的NTLM认证已配置(自认为正确)
  • 用户拥有该列表的完全访问权限
  • 安装IIS CORS模块后,在web.config中添加CORS标签时,服务器立即返回500 Internal Server Error
  • CORS配置已生效,未观察到CORS相关错误

解决方案及优化建议

1. 修正CORS重写规则正则表达式

当前正则^(https?://(.*\.)?domain1\.com|domain2\.com)$未匹配shptest2.domain2.com的完整Origin格式,修改为:

<add input="{HTTP_ORIGIN}" pattern="^(https?://(.*\.)?domain1\.com|https?://(.*\.)?domain2\.com)$" />

确保跨域请求的Origin能被正确识别并返回Access-Control-Allow-Origin头。

2. 允许OPTIONS预检请求匿名访问

NTLM认证下,浏览器发送的OPTIONS预检请求不会携带凭证,需确保IIS允许该请求匿名通过:

  • 在shpdatabase.domain3.com的IIS站点启用匿名认证(同时保留NTLM认证)
  • 在web.config的<security>节点下添加:
<authorization>
  <allow verbs="OPTIONS" users="*" />
  <deny users="?" />
</authorization>

避免预检阶段返回401错误。

3. 调整REST API请求路径

放弃通过SP.AppContextSite的代理方式,直接调用目标站点API:

const url = `${hostWebUrl}/_api/web/lists/getbytitle('test01')/items?$top=10`;

减少认证代理环节的复杂度。

4. 修复IIS CORS模块500错误

若要使用官方IIS CORS模块,需删除原有自定义CORS头和rewrite规则,替换为正确配置:

<cors enabled="true" failUnlistedOrigins="true">
  <add origin="https://shptest2.domain2.com" allowCredentials="true">
    <allowHeaders allowAllRequestedHeaders="true" />
    <allowMethods>
      <add method="GET" />
      <add method="POST" />
      <add method="OPTIONS" />
      <add method="PUT" />
      <add method="DELETE" />
    </allowMethods>
  </add>
</cors>

安装模块后需重启IIS,确保配置生效。

5. 解决NTLM双跳限制

NTLM存在跨域凭证转发的双跳限制,可通过以下方式解决:

  • 在域控制器中配置Kerberos约束委派,允许shptest2.domain2.com的应用池账户委派到shpdatabase.domain3.com的SPN
  • 先将测试页面部署到shpdatabase.domain3.com,验证非跨域场景下API正常,再逐步排查跨域问题

6. 优化浏览器请求配置

确保请求携带完整认证上下文,添加必要请求头:

const response = await fetch(url, {
    method: 'GET',
    headers: {
        'Accept': 'application/json;odata=verbose',
        // 若页面部署在SharePoint中,可添加请求摘要头
        // 'X-RequestDigest': document.getElementById('__REQUESTDIGEST').value
    },
    credentials: 'include',
    mode: 'cors'
});

内容的提问来源于stack exchange,提问作者Lukas Kutka

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 10:30:56