keyring.get_password()读取Windows凭据管理器凭证时抛出NameError
Windows环境keyring调用凭据库报win32cred/pywintypes未定义故障处理
问题背景
- 运行环境:Windows系统、Python 3.10
- 使用目的:通过
keyring库安全管理pyodbc、sqlalchemy连接数据库所需的密码,避免明文硬编码在代码中 - 前置操作:已参考官方公开issue说明手动配置keyring使用Windows凭据库(WinVault)作为后端,所有报错涉及的依赖包均已完成安装
- 测试代码:
from keyring.backends import Windows import keyring keyring.set_keyring(Windows.WinVaultKeyring()) keyring.get_password("Service", "Username")
- 运行抛出的错误信息:
Traceback (most recent call last): File ".\Python310\lib\site-packages\keyring\backends\Windows.py", line 109, in _get_password res = win32cred.CredRead( NameError: name 'win32cred' is not defined During handling of the above exception, another exception occurred: Traceback (most recent call last): File "<stdin>", line 1, in <module> File ".\Python310\lib\site-packages\keyring\core.py", line 55, in get_password return get_keyring().get_password(service_name, username) File ".\Python310\lib\site-packages\keyring\backends\Windows.py", line 99, in get_password res = self._get_password(service) File ".\Python310lib\site-packages\keyring\backends\Windows.py", line 112, in _get_password except pywintypes.error as e: NameError: name 'pywintypes' is not defined
- 当前环境已安装包及版本:
| 包名 | 版本号 |
|---|---|
| astroid | 2.9.3 |
| backcall | 0.2.0 |
| certifi | 2021.10.8 |
| cffi | 1.15.0 |
| charset-normalizer | 2.0.12 |
| cloudpickle | 2.1.0 |
| colorama | 0.4.4 |
| comtypes | 1.1.11 |
| cryptography | 37.0.2 |
| dask | 2022.6.1 |
| executing | 0.8.3 |
| fsspec | 2022.5.0 |
| greenlet | 1.1.2 |
| idna | 3.3 |
| ipython-genutils | 0.2.0 |
| isort | 5.10.1 |
| keyring | 23.6.0 |
| lazy-object-proxy | 1.7.1 |
| locket | 1.0.0 |
| mccabe | 0.6.1 |
| mistune | 0.8.4 |
| MouseInfo | 0.1.3 |
| numpy | 1.22.3 |
| opencv-python | 4.5.5.64 |
| packaging | 21.3 |
| pandas | 1.4.1 |
| partd | 1.2.0 |
| pickleshare | 0.7.5 |
| Pillow | 9.1.1 |
| pip | 22.1.2 |
| platformdirs | 2.5.1 |
| pure-eval | 0.2.2 |
| PyAutoGUI | 0.9.53 |
| pycparser | 2.21 |
| PyGetWindow | 0.0.9 |
| pylint | 2.12.2 |
| PyMsgBox | 1.0.9 |
| pyodbc | 4.0.32 |
| pyparsing | 3.0.7 |
| pyperclip | 1.8.2 |
| PyQt6 | 6.3.1 |
| PyQt6-Qt6 | 6.3.1 |
| PyQt6-sip | 13.4.0 |
| PyRect | 0.2.0 |
| PyScreeze | 0.1.28 |
| pytesseract | 0.3.9 |
| python-bidi | 0.4.2 |
| python-dateutil | 2.8.2 |
| pytweening | 1.0.4 |
| pytz | 2022.1 |
| PyWavelets | 1.3.0 |
| pywin32 | 303 |
| pywin32-ctypes | 0.2.0 |
| pywinauto | 0.6.8 |
| PyYAML | 6 |
| requests | 2.27.1 |
| scipy | 1.8.0 |
| Send2Trash | 1.8.0 |
| setuptools | 58.1.0 |
| six | 1.16.0 |
| SQLAlchemy | 1.4.39 |
| sudo | 1.0.0 |
| tifffile | 2022.3.16 |
| toml | 0.10.2 |
| toolz | 0.11.2 |
| torch | 1.11.0 |
| torchaudio | 0.11.0 |
| torchvision | 0.12.0 |
| traitlets | 5.1.1 |
| typing_extensions | 4.1.1 |
| urllib3 | 1.26.9 |
| wcwidth | 0.2.5 |
| webencodings | 0.5.1 |
| wrapt | 1.13.3 |
故障原因
该报错和keyring库本身无关,根源是当前环境安装的pywin32==303版本存在已知兼容问题:该版本在部分Python3.10环境下安装时,不会自动执行模块路径注册脚本,导致win32cred、pywintypes等pywin32附属模块虽然已存在于本地安装目录,但不在Python的导入搜索路径中,keyring的Windows后端懒加载这两个模块失败,就会直接抛出NameError。
解决方法
按以下优先级操作,每步完成后重启Python解释器再测试:
- 手动执行pywin32路径注册脚本
打开命令行切换到当前Python环境的根目录,执行命令:
命令行输出python Scripts/pywin32_postinstall.py -installThe pywin32 extensions were successfully installed即代表注册完成。 - 若执行注册脚本后仍报错,直接降级pywin32到无该问题的稳定版本:
pip install pywin32==302 --force-reinstall - 功能验证
先执行密码写入操作:
再调用keyring.set_password("Service", "Username", "testpwd123")keyring.get_password("Service", "Username"),能正常返回testpwd123即代表功能正常,后续可直接读取存储的密码拼接pyodbc、SQLAlchemy连接串,无需明文写密码。
内容的提问来源于stack exchange,提问作者Isaacnfairplay
相关产品推荐
相关产品推荐

