从SharePoint下载文件触发AADSTS50005认证失败问题咨询
shareplum、sharepy两个库已经多年没有更新核心认证逻辑,用的还是微软早就淘汰的旧版SharePoint表单认证流程,发认证请求的时候不会携带Azure AD条件访问要求的设备平台标识、合规声明字段,最后AAD直接把请求来源判定为Unknown平台,抛出你看到的报错:
Error authenticating against Office 365. Error from Office 365:', "AADSTS50005: User tried to log in to a device from a platform (Unknown) that's currently not supported through Conditional Access policy. Supported device platforms are: iOS, Android, Mac, and Windows flavors."
这个报错和你本地实际运行的Windows系统没有关系,纯粹是库发出的请求本身不符合租户侧的访问校验规则。顺带一提,这两个库也完全不支持目前绝大多数Office365租户强制开启的MFA多因素认证,本身已经不适配当前的SharePoint Online认证规则。
如果只是临时一次性下载文件,可以直接绕过库自带的账号密码认证逻辑:
- 先在本地浏览器正常登录对应SharePoint站点,打开浏览器开发者工具的网络面板,抓取认证成功后请求里携带的
FedAuth、rtFa两个Cookie字段 - 手动把这两个Cookie注入到shareplum/sharepy的请求会话中,就可以直接访问文件资源
- 注意这个方法拿到的Cookie有有效期,一般几小时到几天不等,过期之后需要重新抓取,不适合长期运行的自动化任务
推荐直接用还在持续维护、适配了最新认证规则的方案实现需求,从根源上规避认证拦截问题:
- 用微软生态官方维护的
Office365-REST-Python-Client库,支持全模式OAuth2.0认证,不会触发条件访问的平台校验,基础使用代码如下:
from office365.sharepoint.client_context import ClientContext from office365.runtime.auth.client_credential import ClientCredential import os # 基础配置 site_url = "你的SharePoint站点根地址" client_id = "Azure AD注册应用的客户端ID" client_secret = "Azure AD应用对应的客户端密钥" local_save_dir = "./sharepoint_downloads" os.makedirs(local_save_dir, exist_ok=True) # 初始化认证上下文(走应用凭证模式,不校验设备平台) ctx = ClientContext(site_url).with_credentials(ClientCredential(client_id, client_secret)) # 单个文件下载 def download_single_file(server_relative_path: str, local_file_name: str): local_path = os.path.join(local_save_dir, local_file_name) with open(local_path, "wb") as local_file: target_file = ctx.web.get_file_by_server_relative_url(server_relative_path) target_file.download(local_file).execute_query() # 指定文件夹批量下载 def batch_download_folder(folder_relative_path: str): target_folder = ctx.web.get_folder_by_server_relative_url(folder_relative_path) all_files = target_folder.files ctx.load(all_files) ctx.execute_query() for sp_file in all_files: local_path = os.path.join(local_save_dir, sp_file.name) with open(local_path, "wb") as local_file: sp_file.download(local_file).execute_query() if __name__ == "__main__": # 调用示例:下载单个文件 # download_single_file("/sites/你的站点名/Shared%20Documents/test.docx", "test.docx") # 调用示例:批量下载指定文件夹 # batch_download_folder("/sites/你的站点名/Shared%20Documents/目标文件夹名") pass
用这个方案需要提前在Azure AD里注册一个应用,给应用分配对应SharePoint站点的读取权限,配好客户端密钥之后就可以长期稳定调用,不受MFA、条件访问策略影响。
- 如果不想额外注册Azure应用,在本地Windows环境下可以走微软官方的设备码认证流程,通过
msal库获取用户委托身份的合法token,携带token调用SharePoint REST接口拉取文件,这个认证流程是微软官方实现的,会正确识别Windows设备平台,不会触发AADSTS50005拦截。 - 如果是生产环境对稳定性要求高,可以直接调用Microsoft Graph提供的SharePoint文件接口,提前给应用授予
Sites.Read.All委派或应用权限,拿到token之后直接发GET请求下载文件即可,是目前兼容性最高的实现方式。
内容的提问来源于stack exchange,提问作者saj1807

