配置服务器场混合功能后,提供程序托管的外接程序SharePoint HTTP 401 错误

症状

请考虑以下应用场景: 您具有注册为 (PHA) 且包含 RegisteredIssuerName SharePoint 2013 或 SharePoint 2016 服务器场的原始服务器场值的现有已部署的提供程序托管的外接程序,并且/或在服务器场中创建 工作流管理器 关联。 RealmID

在此方案中,当您在服务器场中配置混合功能SharePoint访问这些 PHA 时,这些 PHA 将停止运行。 此外,当您被定向到外接程序时,您会收到 HTTP 401 错误消息。

备注

PHA 可能包括外部托管的 Web 应用程序、服务、数据库或 SharePoint组件。 如果先配置混合功能,然后在 SharePoint 2013 或 SharePoint 2016 服务器场中部署提供程序托管的外接程序和/或 工作流管理器,则不存在此问题。

原因

为 SharePoint 2013 或 SharePoint 2016 配置 SharePoint 混合功能会中断在配置混合功能之前创建的服务器到服务器 (S2S) 信任。 当您尝试使用云 SSA 上线脚本或混合选取器建立 S2S 信任时,将更新内部部署服务器场的身份验证领域,以匹配 Office 365 租户上下文 ID。 该脚本使用 Set-SPAuthenticationRealm cmdlet 设置身份验证领域。 更改身份验证领域后,现有SharePoint外接程序将无法进行身份验证。

发生此身份验证失败的原因是提供程序托管的外接程序如何有权访问SharePoint。 SharePoint值关联 SPTrustedSecurityTokenIssuers 外接程序 IssuerId 。 根据请求,外接程序会尝试从 STS 安全令牌颁发者 (令牌) 。 令牌颁发者绑定到身份验证领域。 域更改后,SharePoint外接程序将不再能成功进行身份验证。 服务器场中仍然存在具有正确颁发者 ID 的受信任令牌颁发者。 但是,它与以前的身份验证领域相关联。 实际 RegisteredIssuerName 值为 IssuerId@OldAuthRealmGuid ,其中 oldAuthRealmGuid 的值不再与当前值 AuthRealmGuid 匹配。 加载项无法进行身份验证,因为 STS 找不到匹配的令牌颁发者。

以下错误消息记录到 ULS 日志中,并清楚地指示令牌颁发者不再受信任,因为令牌颁发者的值不再 RealmID 与服务器场匹配:

SPApplicationAuthenticationModule:无法对请求进行身份验证,错误未知。 异常详细信息:System.IdenitytModel.Tokens.SecurityTokenException:令牌的问题不是受信任的颁发者。

解决方案

配置混合时 RealmID ,将更改为与 Office365 订阅的租户 ID 相匹配。 这会导致外接程序停止工作,如"症状"部分所述。 若要SharePoint外接程序功能,请通过使用包含新领域 ID 的值注册提供程序 RegisteredIssuerName 托管的外接程序。 然后,重新应用每个外接程序实例的外接程序权限。

若要修复与提供程序托管的外接程序和混合功能关联的身份验证相关问题,请按照以下步骤操作:

  1. 运行以下脚本以发现在 Web 应用程序上部署的所有应用程序实例:

    在下面的脚本中,将 {0} 替换为 Web 应用程序。 脚本的输出是应用程序标题、应用客户端 ID 以及所有提供程序托管的外接程序的目标 Web。这些值将用作步骤 3 中的输入。

     Add-PsSnapin Microsoft.SharePoint.PowerShell
     Add-PsSnapin Microsoft.SharePoint.PowerShell
     $webApp = Get-SPWebApplication "{0}"
     foreach($site in $webApp.Sites){
     foreach($web in $site.AllWebs)
     {
     $appInstance = Get-SPAppInstance -Web $web.Url | ? {$_.LaunchUrl -notlike "~appWebUrl*"} | select Title, AppPrincipalId
     if($appInstance -ne $null)
     {
     foreach ($instance in $appInstance)
     {
     $tmp = $instance.AppPrincipalId.Split('|@',[System.StringSplitOptions]::RemoveEmptyEntries)
     $appInfo = $instance.Title + " - " + $tmp[$tmp.Count - 2] + " - " + $web.Url
     Write-Output $appInfo
     }
     }
     }
     }
    
  2. 通过 以下脚本更新 SPTrustedSecurityTokenIssuers:

     $NewRealm = Get-SPAuthenticationRealm
     $sts = Get-SPTrustedSecurityTokenIssuer | ? {$_.Name -ne 'EvoSTS-Trust' -and $_.Name -ne 'ACS_STS'} | Select RegisteredIssuerName
     $realm = $sts | ?{$_.RegisteredIssuerName -ne $null} | %{$($($_.RegisteredIssuerName).toString().split('@',2)[1]).toString()} | ?{$_ -ne '*' -and $_ -ne $newRealm}
     if($Realm.count -gt 0) {
     $TempRealm = '*@$($NewRealm)'
     $Issuers = Get-SPTrustedSecurityTokenIssuer | ?{$_.Name -ne 'EvoSTS-Trust' -and $_.Name -ne 'ACS_STS' -and $_.RegisteredIssuerName -ne $null -and $_.RegisteredIssuerName -notlike '*@`*' -and $_.RegisteredIssuerName -notlike $TempRealm}
    
     $Guid = [guid]::NewGuid()
     foreach ($Issuer in $Issuers)
     {
     $NameCopy = $Issuer.Name
     $NewIssuerName = $Guid
     $IssuerCertificate = $Issuer.SigningCertificate
     $OldRegisteredIssuerID = $Issuer.RegisteredIssuerName
     $IssuerID = $OldRegisteredIssuerID.Split('@')[0]
     $NewRegisteredIssuerName = $IssuerID + '@' + $NewRealm
     $NewIssuer = New-SPTrustedSecurityTokenIssuer -Name $NewIssuerName -Certificate $IssuerCertificate -RegisteredIssuerName $NewRegisteredIssuerName -IsTrustBroker
     Remove-SPTrustedSecurityTokenIssuer $Issuer -Confirm:$false
     $NewIssuer.Name = $NameCopy
     $NewIssuer.Update()
     }
     }
    
  3. 通过运行以下脚本修复步骤 1 中发现的每个提供程序托管的外接程序:

    在脚本中,将 和 替换为在步骤 {0} {1} {2} 1 中获取的值。

     $appTitle = '{0}'
     $clientID = '{1}'
     $targetWeb = Get-SPWeb '{2}'
     $Scope = 'Site'
     $Right = 'Full Control'
     $authRealm = Get-SPAuthenticationRealm -ServiceContext $targetWeb.Site
     $AppIdentifier = $clientID + '@' + $authRealm
     Register-SPAppPrincipal -NameIdentifier $AppIdentifier -Site $targetWeb -DisplayName $appTitle
     $appPrincipal = Get-SPAppPrincipal -Site $targetWeb -NameIdentifier $AppIdentifier
     Set-SPAppPrincipalPermission -Site $targetWeb -AppPrincipal $appPrincipal -Scope $Scope -Right $Right
    

    若要更新证书的身份验证工作流管理器,请运行以下 cmdlet:

     $workflowproxy = Get-SPWorkflowServiceApplicationProxy
     $webapp = get-spwebapplication
     if ($webapp)
     {
     $webappurl = $webapp[0].url
     $Site=get-spsite $webappurl
     if ($site)
     {
     $workflowaddress = $workflowproxy.GetWorkflowServiceAddress($site)
     $workflowscopename = $workflowproxy.GetWorkflowScopeName($site)
     $TrimScope = '/'+$workflowscopename+'/'
     $wfmaddress = $workflowaddress.TrimEnd($Trimscope)
     }
     }
     $workflowproxy.delete()
     Register-SPWorkflowService -SPSite $Site -WorkflowHostUri $wfmaddress -Force
    

    如果在配置混合功能之前部署了跨服务器场信任方案,请使用以下 TechNet 主题中的方法手动修复这些方案:

更多信息

如果在您实施提供程序托管的外接程序或 工作流管理器 之前配置需要 S2S 的混合工作负载,则外接程序将在更新 cmdlet 后注册,以匹配 Office 365 租户 SPAuthenticationRealm 上下文 ID。 它们始终会正常工作,因为 RealmID 值不会再次更改。 如果添加或重新配置混合工作负载,领域 ID 将保持与租户Office 365相同上下文 ID。

若要在内部部署环境和 SharePoint 之间创建服务器到服务器Office 365,请运行Set-SPAuthenticationRealm

重要

本主题包含一个"警告"部分,该部分警告为特定领域创建的任何访问令牌在更改值后将 SPAuthenticationRealm 不起作用。

若要SharePoint提供程序托管的外接程序,请参阅开始创建提供程序托管SharePoint外接程序

仍然需要帮助? 请转到 SharePoint 社区