You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 04:09:29