C#自定义凭据提供者RDP认证错误问题求助
问题分析与解决方案
你的问题核心在于RDP远程登录场景下,凭据提供者的UpdateRemoteCredential方法未正确适配远程登录的凭据格式。本地交互式会话使用的KerbInteractiveUnlockLogon结构无法直接用于远程RDP认证,必须转换为远程专用的KERB_REMOTE_UNLOCK_LOGON结构,否则会触发"令牌无效"的错误。
1. 修复ICredentialProviderFilter.UpdateRemoteCredential方法
RDP连接时,系统会调用该方法将本地凭据转换为远程认证可用的格式。直接返回原序列化数据是错误的,需要完成以下步骤:
- 解析输入的
KerbInteractiveUnlockLogon结构 - 转换为
KERB_REMOTE_UNLOCK_LOGON结构 - 重新打包并输出新的序列化数据
修改后的代码示例:
public int UpdateRemoteCredential(ref _CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION pcpcsIn, out _CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION pcpcsOut) { pcpcsOut = new _CREDENTIAL_PROVIDER_CREDENTIAL_SERIALIZATION(); try { // 仅处理Kerberos认证包的情况 if (pcpcsIn.ulAuthenticationPackage != CredHelper.Instance.GetKerberosAuthPackageId()) { pcpcsOut = pcpcsIn; return HResult.Ok; } // 解析输入的KerbInteractiveUnlockLogon结构 var kerbInteractive = Marshal.PtrToStructure<KerbInteractiveUnlockLogon>(pcpcsIn.rgbSerialization); // 初始化远程登录结构 var kerbRemote = new KerbRemoteUnlockLogon { LogonId = kerbInteractive.LogonId, MessageType = (int)KerbRemoteLogonMessageType.KerbRemoteUnlockLogon, Credentials = kerbInteractive.Credentials }; // 重新打包远程结构 NativeLogon.KerbRemoteUnlockLogonPack(ref kerbRemote, out IntPtr remoteCredBuffer, out int remoteCredSize); // 设置输出序列化数据 pcpcsOut.clsidCredentialProvider = Statics.CredentialProviderGuid; pcpcsOut.ulAuthenticationPackage = pcpcsIn.ulAuthenticationPackage; pcpcsOut.rgbSerialization = remoteCredBuffer; pcpcsOut.cbSerialization = (uint)remoteCredSize; return HResult.Ok; } catch (Exception ex) { // 异常处理,返回错误 pcpcsOut = pcpcsIn; return HResult.Fail; } }
需要补充对应的Native方法和结构体定义:
// KERB_REMOTE_UNLOCK_LOGON结构 [StructLayout(LayoutKind.Sequential)] public struct KerbRemoteUnlockLogon { public LUID LogonId; public int MessageType; public KerberosInteractiveLogon Credentials; } public enum KerbRemoteLogonMessageType { KerbRemoteUnlockLogon = 2 } // 对应的打包方法 public static class NativeLogon { [DllImport("advapi32.dll", CharSet = CharSet.Unicode)] public static extern bool KerbRemoteUnlockLogonPack(ref KerbRemoteUnlockLogon logonData, out IntPtr buffer, out int bufferSize); }
2. 检查GetSerialization方法的潜在问题
- 确认
usageScenario在RDP场景下是否被正确设置为CredentialProviderUsageScenario.CPUS_LOGON(而非解锁场景) - 验证
KerbInteractiveUnlockLogonInit方法是否正确处理了远程登录的标志位,比如是否设置了KERB_INTERACTIVE_LOGON中的MessageType为KerbInteractiveLogon(而非解锁类型) - 确保
inCredBuffer的内存被正确管理(使用完后需要调用Marshal.FreeHGlobal释放,避免内存泄漏)
3. 关键注意事项
- RDP远程登录和本地交互式登录使用不同的Kerberos认证结构,必须通过
UpdateRemoteCredential完成转换 - 所有非托管内存(如
IntPtr指向的缓冲区)必须在适当的时机释放,防止内存泄漏 - 测试时需确保凭据提供者在远程桌面服务的上下文中有足够的权限
内容的提问来源于stack exchange,提问作者canowar
相关产品推荐
相关产品推荐

