SharePoint 2016本地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
相关产品推荐
相关产品推荐

