使用requests-gssapi对接SPNEGO服务器时认证失败求助
我遇到过几乎一模一样的问题——用requests-gssapi访问内网SAS服务时,明明Kerberos票据正常,却因为发送了Kerberos 5而非SPNEGO的认证头导致401错误。后来发现核心问题是需要显式指定SPNEGO作为认证机制,而不是依赖库的自动选择。
解决步骤
显式指定SPNEGO认证机制
requests-gssapi的HTTPSPNEGOAuth默认可能会根据环境直接选择Kerberos 5认证,但我们需要强制它使用SPNEGO(也就是Chrome和curl采用的Negotiate协商流程)。修改你的代码如下:import requests from requests_gssapi import HTTPSPNEGOAuth, OPTIONAL import gssapi session = requests.Session() # 第一步:获取初始401响应及认证URL r1 = session.get(url) if r1.status_code != 401: print(f"Error! Expected 401 response but got {r1.status_code}") exit(1) auth_url = r1.url # 第二步:使用SPNEGO机制发起认证请求 spnego_auth = HTTPSPNEGOAuth( mutual_authentication=OPTIONAL, mech=gssapi.MechType.SPNEGO ) r2 = session.get(auth_url, auth=spnego_auth) # 验证认证结果 if r2.status_code in (200, 302): print("认证成功!") # 后续可复用session访问其他需要认证的SAS接口 else: print(f"认证失败,状态码:{r2.status_code}")确认Kerberos票据的SPN匹配
用klist命令检查本地Kerberos票据,确保存在对应SAS服务的SPN(格式通常为HTTP/sas-server.your-domain.com@YOUR_REALM)。如果没有匹配的票据,可尝试用kinit重新获取,或确认你的Windows登录账号拥有该服务的访问权限。复用Session保持状态
确保全程使用同一个requests.Session()实例,这样cookies和认证上下文会被保留,适配服务的重定向流程。
失败原因分析
从你的抓包结果可以明确差异:
- Chrome和curl发送的
Authorization: Negotiate头包含SPNEGO的OID(1.3.6.1.5.5.2),这是一个协商机制,会先尝试SPNEGO再按需降级; - 之前的Python请求直接使用了Kerberos 5的OID(1.2.840.113554.1.2.2),跳过了SPNEGO协商步骤,不符合服务的认证要求,因此被拒绝。
显式指定mech=gssapi.MechType.SPNEGO后,requests-gssapi会生成与浏览器、curl完全一致的SPNEGO认证头,匹配服务的认证流程。另外,如果服务不需要双向认证,将mutual_authentication设为OPTIONAL(默认是REQUIRED)可以避免额外的兼容性问题。
内容的提问来源于stack exchange,提问作者capitan

