使用Python证书认证连接SharePoint指定站点报错问题
我尝试用Python的Office365-REST-Python-Client库,通过证书认证连接SharePoint Online:
- 连接根站点
https://mytenant.sharepoint.com时可正常工作 - 连接指定子站点
https://mytenant.sharepoint.com/sites/MySite时出现错误
但以上两种场景在PowerShell中均可正常连接,因此排除配置问题。
PowerShell连接示例
连接根站点
Connect-PnPOnline -Url https://mytenant.sharepoint.com -Tenant mytenant.onmicrosoft.com -ClientId 5fa2148c-d484-444a-bcf1-db632a0fed71 -CertificatePath 'PowershellPnp.pfx' -CertificatePassword $(ConvertTo-Securestring -string "MyCertPassword" -AsPlainText -Force)
连接子站点
Connect-PnPOnline -Url https://mytenant.sharepoint.com/sites/MySite -Tenant mytenant.onmicrosoft.com -ClientId 5fa2148c-d484-444a-bcf1-db632a0fed71 -CertificatePath 'PowershellPnp.pfx' -CertificatePassword $(ConvertTo-Securestring -string "MyCertPassword" -AsPlainText -Force)
以上两种PowerShell操作均无错误。
Python连接代码
连接根站点(正常工作)
site_url = "https://mytenant.sharepoint.com" cert_settings = { 'client_id': '5fa2148c-d484-444a-bcf1-db632a0fed71', 'thumbprint': "D1656C4AAC5CFBB971477230A5FBACCD356829D3", 'cert_path': 'PowershellPnp.pem' } ctx = ClientContext(site_url).with_client_certificate('mytenant.onmicrosoft.com',**cert_settings)
连接子站点(报错)
site_url = "https://mytenant.sharepoint.com/sites/MySite" cert_settings = { 'client_id': '5fa2148c-d484-444a-bcf1-db632a0fed71', 'thumbprint': "D1656C4AAC5CFBB971477230A5FBACCD356829D3", 'cert_path': 'PowershellPnp.pem' } ctx = ClientContext(site_url).with_client_certificate('mytenant.onmicrosoft.com',**cert_settings)
错误信息
ValueError: {'error': 'invalid_resource', 'error_description':
'AADSTS500011: The resource principal named
https://mytenant.sharepoint.com/sites/MySite was not found in the
tenant named mytenant. This can happen if the application has not been
installed by the administrator of the tenant or consented to by any
user in the tenant. You might have sent your authentication request to
the wrong tenant'}
原因分析
这个错误的核心是:Python的Office365-REST-Python-Client库默认会把传入的site_url作为认证请求的资源标识符(resource),但SharePoint Online的资源标识符应该是租户级的根站点URL(即https://mytenant.sharepoint.com),而非子站点路径。
而PowerShell的PnP模块会自动处理这一点,默认使用租户根站点作为resource,所以无论连接根站点还是子站点都能正常获取令牌。
解决方法
在调用with_client_certificate时,显式指定resource参数为租户根站点URL,覆盖库的默认行为:
site_url = "https://mytenant.sharepoint.com/sites/MySite" cert_settings = { 'client_id': '5fa2148c-d484-444a-bcf1-db632a0fed71', 'thumbprint': "D1656C4AAC5CFBB971477230A5FBACCD356829D3", 'cert_path': 'PowershellPnp.pem' } # 显式指定resource为租户根站点 ctx = ClientContext(site_url).with_client_certificate( 'mytenant.onmicrosoft.com', resource='https://mytenant.sharepoint.com', **cert_settings )
这样认证请求会以租户根站点为资源获取令牌,只要应用已获得对应子站点的权限,就能正常访问该子站点。
内容的提问来源于stack exchange,提问作者mannaggia

