Windows 服务使用 AccessToken 模拟用户

问题描述 投票:0回答:1

我有两个应用程序,一个是 Windows 服务(用 .NET 6 编写),另一个是 Winform 应用程序(也是用 .NET 6 编写)。 Winform应用程序处于用户自动启动状态并缩减至系统托盘。 Windows 服务设置为自动启动。

Windows服务和Winform应用程序通过管道连接。现在我想访问我的 (asp.net core) api,它通过我的 Windows 服务使用 Windows 身份验证。为此,我认为我需要模仿。由于我不知道当前登录用户的凭据,我认为我可以简单地通过管道将

WindowsIdentity.Token
传递到我的服务。

像这样:

// ... other server pipe stuff ...
var writer = new StreamWriter(serverPipe) { AutoFlush = true };
await writer.WriteLineAsync(Convert.ToString(WindowsIdentity.GetCurrent().Token));

并在我的 Windows 服务中使用令牌,如下所示:


IntPtr.TryParse(Convert.ToString(TOKEN_FROM_WINFORM_APPLICATION), out var winAuthToken);
return await WindowsIdentity.RunImpersonatedAsync(new SafeAccessTokenHandle(winAuthToken), async () =>
{
    using var client = new HttpClient(new HttpClientHandler
    {
        UseDefaultCredentials = true, // send winAuth token
    });

    var content = new StringContent(body, Encoding.UTF8, "application/json");
    var url = $"{baseUrl}{endpoint}?{query}";

    var response = requestMethod switch
    {
        RequestMethod.Get => await client.GetAsync(url),
        RequestMethod.Post => await client.PostAsync(url, content),
        _ => throw new ArgumentOutOfRangeException(nameof(requestMethod), requestMethod, null)
    };

    return await response.Content.ReadAsStringAsync();
});

此方法会导致

System.ArgumentException: "Invalid token for impersonation - it cannot be duplicated.
异常。

我也尝试过复制令牌,但仍然遇到相同的错误:

[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int DuplicateToken(IntPtr hToken, int impersonationLevel, ref IntPtr hNewToken);

IntPtr token = default;
if (DuplicateToken(WindowsIdentity.GetCurrent().Token, 3, ref token) != 0)
{
    await writer.WriteLineAsync(Convert.ToString(token));
}

microsoft 文档以及我在 stackoverflow 上能找到的所有内容仅显示了如何使用客户端凭据进行模拟。

我还看到了一些使用 OpenProcessApi 的方法,但我不知道我需要哪个

ProcessHandle
DesiredAccess

如何使用当前登录用户的令牌在我的WebApi上执行Windows身份验证?

感谢您的帮助!

编辑:好吧,我发现(在这个答案中)我可以将

OpenProcessApi
与登录用户的processId一起使用来获得访问权限,但由于我已经运行了一个Winform应用程序,因此在那里获得它会更容易,不是吗?

我还发现使用

WindowsIndentity.Token
绝对是错误的,因为here指出它不能用作 userToken。

c# .net windows-services windows-authentication impersonation
1个回答
0
投票

我在 Github 上发现了一个非常有用的类,它实现了 win32 api 方法WTSQueryUserToken,它正是我正在寻找的。它为当前登录的用户返回一个

AccessToken
。我只需要将 TokenType 切换为
TOKEN_TYPE.TokenImpersonation

现在我的代码如下所示(我将

ProcessExtensions.cs
重命名为
Win32Api.cs
):

var userToken = IntPtr.Zero;
Win32Api.GetSessionUserToken(ref userToken);

var identity = new WindowsIdentity(userToken);

// impersonate current logged in user        
return await WindowsIdentity.RunImpersonatedAsync(identity.AccessToken, async () =>
{
    using var client = new HttpClient(new HttpClientHandler
    {
        UseDefaultCredentials = true, // send winAuth token
    });

    var content = new StringContent(body, Encoding.UTF8, "application/json");
    var url = $"{baseUrl}{endpoint}?{query}";

    var response = requestMethod switch
    {
        RequestMethod.Get => await client.GetAsync(url),
        RequestMethod.Post => await client.PostAsync(url, content),
        _ => throw new ArgumentOutOfRangeException(nameof(requestMethod), requestMethod, null)
    };

    return await response.Content.ReadAsStringAsync();
});


这就像一个魅力!我希望这对未来的读者有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.