在操作之前使用C#传递服务器共享凭据

时间:2010-10-13 09:44:30

标签: c# windows networking

我的应用程序使用网络上的共享目录(Windows),并且我希望仅在给定用户和密码的网络上提供该共享。 有没有办法在对此网络资源进行任何操作之前通过身份验证? *我没有使用域名。

非常感谢你!

1 个答案:

答案 0 :(得分:1)

我不完全确定如何传递IO操作的凭据,但通常我会使用模拟类来模拟或委派特定代码块的用户凭据。

E.g:

/// <summary>
/// Provides a mechanism for impersonating a user.  This is intended to be disposable, and
/// used in a using ( ) block.
/// </summary>
public class Impersonation : IDisposable
{
    #region Externals
    [DllImport("advapi32.dll", SetLastError = true)]
    private static extern bool LogonUser(
        string lpszUsername,
        string lpszDomain,
        string lpszPassword,
        int dwLogonType,
        int dwLogonProvider,
        out IntPtr phToken);

    [DllImport("advapi32.dll", SetLastError = true)]
    private extern static bool DuplicateToken(IntPtr ExistingTokenHandle, int
       SECURITY_IMPERSONATION_LEVEL, out IntPtr DuplicateTokenHandle);

    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool CloseHandle(IntPtr hObject);
    #endregion

    #region Fields
    private IntPtr token;
    private IntPtr tokenDuplicate;

    private WindowsIdentity identity;
    private WindowsImpersonationContext context;

    private readonly string domain;
    private readonly string username;
    private readonly string password;
    private ImpersonationLevel level;
    #endregion

    #region Constructor
    /// <summary>
    /// Initialises a new instance of <see cref="Impersonation"/>.
    /// </summary>
    /// <param name="domain">The domain of the target user.</param>
    /// <param name="username">The target user to impersonate.</param>
    /// <param name="password">The target password of the user to impersonate.</param>
    public Impersonation(string domain, string username, string password)
    {
        this.domain = domain;
        this.username = username;
        this.password = password;
        this.level = ImpersonationLevel.Impersonation;

        Logon();
    }

    /// <summary>
    /// Initialises a new instance of <see cref="Impersonation"/>.
    /// </summary>
    /// <param name="domain">The domain of the target user.</param>
    /// <param name="username">The target user to impersonate.</param>
    /// <param name="password">The target password of the user to impersonate.</param>
    /// <param name="level">The security level of this impersonation.</param>
    public Impersonation(string domain, string username, string password, ImpersonationLevel level)
    {
        this.domain = domain;
        this.username = username;
        this.password = password;
        this.level = level;

        Logon();
    }
    #endregion

    #region Methods
    /// <summary>
    /// Reverts the impersonation.
    /// </summary>
    public void Dispose()
    {
        if (context != null)
            context.Undo();

        if (token != IntPtr.Zero)
            CloseHandle(token);

        if (tokenDuplicate != IntPtr.Zero)
            CloseHandle(tokenDuplicate);
    }

    /// <summary>
    /// Performs the logon.
    /// </summary>
    private void Logon()
    {
        if (LogonUser(username, domain, password, 2, 0, out token))
        {
            if (DuplicateToken(token, (int)level, out tokenDuplicate))
            {
                identity = new WindowsIdentity(tokenDuplicate);
                context = identity.Impersonate();
            }
            else
            {
                throw new SecurityException("Unable to impersonate the user.");
            }
        }
        else
        {
            throw new SecurityException("The login details you have entered were incorrect.");
        }
    }
    #endregion
}

/// <summary>
/// Defines the possible security levels for impersonation.
/// </summary>
public enum ImpersonationLevel
{
    /// <summary>
    /// Anonymous access, the process is unable to identify the security context.
    /// </summary>
    Anonymous = 0,
    /// <summary>
    /// The process can identify the security context.
    /// </summary>
    Identification = 1,
    /// <summary>
    /// The security context can be used to access local resources.
    /// </summary>
    Impersonation = 2,
    /// <summary>
    /// The security context can be used to access remote resources.
    /// </summary>
    Delegation = 3
}

现在,它确实涉及一点P / Invoke,但最终结果是:

class Program
{
    static void Main(string[] args)
    {
        using (var impersonation = new Impersonation("domain", "username", "password", ImpersonationLevel.Delegation))
        {
            // Do remote operations here.
        }
    }
}

对于给定的代码段,您可以模拟所需的用户来执行操作。如果在using块中使用,则在执行该段代码之后,将恢复模拟并关闭句柄。

如果您不使用使用区块,则需要确保致电Dispose以清除所有内容。