配置 SharePoint 场混合功能后提供程序托管的加载项停止工作并出现 HTTP 401 错误

症状

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

在此方案中,在场中配置 SharePoint 混合功能后访问这些 PHA 时,PHA 将停止运行。 此外,当定向到加载项时,你会收到 HTTP 401 错误消息。

注意

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

原因

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

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

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

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

解决方案

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

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

  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 中找到的每个提供程序托管的外接程序:

    在脚本中,将 和 {2} 替换为{0}{1}在步骤 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 以匹配 Microsoft 365 租户上下文 ID 后SPAuthenticationRealm注册加载项。 它们将始终正常工作,因为 RealmID 值不会再次更改。 如果添加或重新配置混合工作负载,则领域 ID 与 Microsoft 365 租户上下文 ID 保持相同。

若要在本地 SharePoint 环境和 Microsoft 365 之间创建服务器到服务器信任,请运行 Set-SPAuthenticationRealm

重要

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

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

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