自定义凭据提供器(Custom Credential Provider):如何通过RDP仅输一次密码?
自定义凭据提供器实现「密码+OTP」单次输入的可行方案
核心逻辑:绕开默认两次密码验证流程
官方文档说不可行,是因为默认凭据提供器的流程锁死了「用户名+密码」的两次提交,但实际可以通过自定义登录字段布局和拦截验证请求实现单次输入密码+OTP:
- 把密码框和OTP框放在同一组登录界面,让用户一次填完所有信息
- 自己接管验证逻辑,把密码和OTP一起发给身份验证服务,不走系统默认的两次密码校验
具体实现步骤
1. 改登录界面的字段布局
在ICredentialProviderCredential的实现类里,别用默认的两次密码字段,直接加一个OTP输入框:
// 定义界面显示的字段状态 FIELD_STATE_PAIR fieldStates[] = { {CPFS_DISPLAY_IN_SELECTED_TILE, CPFS_DISPLAY_IN_SELECTED_TILE}, // 用户名 {CPFS_DISPLAY_IN_SELECTED_TILE, CPFS_DISPLAY_IN_SELECTED_TILE}, // 密码 {CPFS_DISPLAY_IN_SELECTED_TILE, CPFS_DISPLAY_IN_SELECTED_TILE} // OTP验证码 }; // 定义字段类型和显示文本 FIELD_DESCRIPTOR fieldDescs[] = { {CPFT_EDIT_TEXT, L"用户名", NULL}, {CPFT_PASSWORD, L"密码", NULL}, {CPFT_EDIT_TEXT, L"OTP验证码", NULL} };
这样用户在登录页就能看到三个输入框,一次完成所有信息输入。
2. 接管验证请求,自定义校验逻辑
在ICredentialProviderCredential::GetSerialization方法里,别直接返回默认的密码序列化数据,按以下步骤处理:
- 先获取用户输入的密码和OTP内容
- 把密码和OTP按约定格式拼接(比如用分隔符
|连起来),或者单独传给你的OTP验证服务 - 调用AD的
LogonUser接口或者第三方OTP验证接口,确认身份合法后,再生成符合系统要求的序列化数据返回给系统
3. 堵死二次密码验证的触发路径
默认流程里系统会触发二次密码请求,这时候要在ICredentialProvider::GetCredentialCount和ICredentialProvider::GetCredentialAt方法里,确保只返回一个凭据实例,并且在验证通过后,不再触发二次输入的逻辑。
4. 踩坑提示
- 别直接硬堆MultiotpCPV2RDP和Stack Overflow的代码,先拆核心:MultiotpCPV2RDP的OTP校验逻辑,Stack Overflow里的自定义字段布局逻辑,再整合
- 重点盯
ICredentialProviderCredential::SetSelected和GetSerialization这两个方法,这俩是控制界面显示和验证流程的核心 - 系统会缓存输入内容,验证失败后要清空OTP字段,避免残留数据影响下一次输入
内容的提问来源于stack exchange,提问作者z0rkiy
相关产品推荐
相关产品推荐

