我们遇到一个有趣的情况,需要解决,和我搜索已景点是否需要.因此,我呼吁所以社会为帮助。

问题是这个:我们有必要访问的编程方式共享文件,是不是在我们的领域,而不是在一个受信赖的外部域通过远程文件共享/UNC。当然,我们需要提供凭证的远程机器。

通常,一个解决了这个问题的两个方面:

  1. 地图的文件共享作为一个驱动和供应的全权证书的时间。这通常是使用 NET USE 命令或Win32职能重复 NET USE.
  2. 访问该文件有一个UNC路径,如果远程计算机上域,并确保该账户在其中运行的程序是重复(包括密码)远程机器上作为一个本地用户。基本上利用事实上,窗户将自动提供的当前用户的凭据,当用户试图访问一个共用的文件。
  3. 不使用远程文件的分享。使用FTP(或一些其他手段)传送文件,它的工作在当地,然后将其传送回去。

对于各种和杂的原因,我们的安全/网络建筑师已经拒绝了第一个两种方法。第二种方法显然是一个安全洞;如果将远程计算机遭到破坏,当地的计算机现在的风险。第一种做法是不能令人满意,因为新安装的驱动是一个共享的资源可用于其他方案在当地的计算机在文件访问过该程序。即使它很可能使该临时性的,它仍然是一个洞他们的意见。

他们打开到第三种选择,但远程网络管理员坚持在蔽而不是FTPS,并FtpWebRequest仅支持FTPS.蔽 更多的防火墙-友好的选项,有几个图书馆我可以用这种做法,但我愿意降低我的依赖性,如果我可以。

我已经搜查MSDN为任何一个管理或win32装置的使用远程文件的分享,但我没有拿出任何有用的。

所以我问:是否有另一种方式?我有没有错过一个超级秘密win32功能做什么我想要什么?或者我必须追求的一些变种备选方案3的?

有帮助吗?

解决方案

的方式来解决你的问题是使用Win32API叫 WNetUseConnection.
使用这一功能连接到一个UNC路径与身份验证,不要地图驱动.

这将允许连接到一个远程机器,即使它不是在同一领域,即使它有一个不同的用户名和密码。

一旦你使用WNetUseConnection,你将能够访问该文件通过一个UNC的道路,因为如果你是在同一领域。最好的办法可能是通过管理建立在共享。
例如:\\计算机名\c$\程序files\Folder\file.txt

这里是一些样品C#代码使用WNetUseConnection.

注意,为NetResource,你应该通过空的lpLocalName和lpProvider.该dwType应RESOURCETYPE_DISK.该lpRemoteName应\\计算机名.

其他提示

人们在寻找一个快速的解决方案,可以使用 NetworkShareAccesser 我最近写的(基于 这个答案 (感谢这么多!)):

使用:

using (NetworkShareAccesser.Access(REMOTE_COMPUTER_NAME, DOMAIN, USER_NAME, PASSWORD))
{
    File.Copy(@"C:\Some\File\To\copy.txt", @"\\REMOTE-COMPUTER\My\Shared\Target\file.txt");
}

警告: 请让绝对肯定的,那 DisposeNetworkShareAccesser 被称为(即使你的应用程序的崩溃!), 否则打开连接将保持在窗。你可以看到所有的开放式连接通过打开的 cmd 迅速和客 net use.

代码:

/// <summary>
/// Provides access to a network share.
/// </summary>
public class NetworkShareAccesser : IDisposable
{
    private string _remoteUncName;
    private string _remoteComputerName;

    public string RemoteComputerName
    {
        get
        {
            return this._remoteComputerName;
        }
        set
        {
            this._remoteComputerName = value;
            this._remoteUncName = @"\\" + this._remoteComputerName;
        }
    }

    public string UserName
    {
        get;
        set;
    }
    public string Password
    {
        get;
        set;
    }

    #region Consts

    private const int RESOURCE_CONNECTED = 0x00000001;
    private const int RESOURCE_GLOBALNET = 0x00000002;
    private const int RESOURCE_REMEMBERED = 0x00000003;

    private const int RESOURCETYPE_ANY = 0x00000000;
    private const int RESOURCETYPE_DISK = 0x00000001;
    private const int RESOURCETYPE_PRINT = 0x00000002;

    private const int RESOURCEDISPLAYTYPE_GENERIC = 0x00000000;
    private const int RESOURCEDISPLAYTYPE_DOMAIN = 0x00000001;
    private const int RESOURCEDISPLAYTYPE_SERVER = 0x00000002;
    private const int RESOURCEDISPLAYTYPE_SHARE = 0x00000003;
    private const int RESOURCEDISPLAYTYPE_FILE = 0x00000004;
    private const int RESOURCEDISPLAYTYPE_GROUP = 0x00000005;

    private const int RESOURCEUSAGE_CONNECTABLE = 0x00000001;
    private const int RESOURCEUSAGE_CONTAINER = 0x00000002;


    private const int CONNECT_INTERACTIVE = 0x00000008;
    private const int CONNECT_PROMPT = 0x00000010;
    private const int CONNECT_REDIRECT = 0x00000080;
    private const int CONNECT_UPDATE_PROFILE = 0x00000001;
    private const int CONNECT_COMMANDLINE = 0x00000800;
    private const int CONNECT_CMD_SAVECRED = 0x00001000;

    private const int CONNECT_LOCALDRIVE = 0x00000100;

    #endregion

    #region Errors

    private const int NO_ERROR = 0;

    private const int ERROR_ACCESS_DENIED = 5;
    private const int ERROR_ALREADY_ASSIGNED = 85;
    private const int ERROR_BAD_DEVICE = 1200;
    private const int ERROR_BAD_NET_NAME = 67;
    private const int ERROR_BAD_PROVIDER = 1204;
    private const int ERROR_CANCELLED = 1223;
    private const int ERROR_EXTENDED_ERROR = 1208;
    private const int ERROR_INVALID_ADDRESS = 487;
    private const int ERROR_INVALID_PARAMETER = 87;
    private const int ERROR_INVALID_PASSWORD = 1216;
    private const int ERROR_MORE_DATA = 234;
    private const int ERROR_NO_MORE_ITEMS = 259;
    private const int ERROR_NO_NET_OR_BAD_PATH = 1203;
    private const int ERROR_NO_NETWORK = 1222;

    private const int ERROR_BAD_PROFILE = 1206;
    private const int ERROR_CANNOT_OPEN_PROFILE = 1205;
    private const int ERROR_DEVICE_IN_USE = 2404;
    private const int ERROR_NOT_CONNECTED = 2250;
    private const int ERROR_OPEN_FILES = 2401;

    #endregion

    #region PInvoke Signatures

    [DllImport("Mpr.dll")]
    private static extern int WNetUseConnection(
        IntPtr hwndOwner,
        NETRESOURCE lpNetResource,
        string lpPassword,
        string lpUserID,
        int dwFlags,
        string lpAccessName,
        string lpBufferSize,
        string lpResult
        );

    [DllImport("Mpr.dll")]
    private static extern int WNetCancelConnection2(
        string lpName,
        int dwFlags,
        bool fForce
        );

    [StructLayout(LayoutKind.Sequential)]
    private class NETRESOURCE
    {
        public int dwScope = 0;
        public int dwType = 0;
        public int dwDisplayType = 0;
        public int dwUsage = 0;
        public string lpLocalName = "";
        public string lpRemoteName = "";
        public string lpComment = "";
        public string lpProvider = "";
    }

    #endregion

    /// <summary>
    /// Creates a NetworkShareAccesser for the given computer name. The user will be promted to enter credentials
    /// </summary>
    /// <param name="remoteComputerName"></param>
    /// <returns></returns>
    public static NetworkShareAccesser Access(string remoteComputerName)
    {
        return new NetworkShareAccesser(remoteComputerName);
    }

    /// <summary>
    /// Creates a NetworkShareAccesser for the given computer name using the given domain/computer name, username and password
    /// </summary>
    /// <param name="remoteComputerName"></param>
    /// <param name="domainOrComuterName"></param>
    /// <param name="userName"></param>
    /// <param name="password"></param>
    public static NetworkShareAccesser Access(string remoteComputerName, string domainOrComuterName, string userName, string password)
    {
        return new NetworkShareAccesser(remoteComputerName,
                                        domainOrComuterName + @"\" + userName,
                                        password);
    }

    /// <summary>
    /// Creates a NetworkShareAccesser for the given computer name using the given username (format: domainOrComputername\Username) and password
    /// </summary>
    /// <param name="remoteComputerName"></param>
    /// <param name="userName"></param>
    /// <param name="password"></param>
    public static NetworkShareAccesser Access(string remoteComputerName, string userName, string password)
    {
        return new NetworkShareAccesser(remoteComputerName, 
                                        userName,
                                        password);
    }

    private NetworkShareAccesser(string remoteComputerName)
    {
        RemoteComputerName = remoteComputerName;               

        this.ConnectToShare(this._remoteUncName, null, null, true);
    }

    private NetworkShareAccesser(string remoteComputerName, string userName, string password)
    {
        RemoteComputerName = remoteComputerName;
        UserName = userName;
        Password = password;

        this.ConnectToShare(this._remoteUncName, this.UserName, this.Password, false);
    }

    private void ConnectToShare(string remoteUnc, string username, string password, bool promptUser)
    {
        NETRESOURCE nr = new NETRESOURCE
        {
            dwType = RESOURCETYPE_DISK,
            lpRemoteName = remoteUnc
        };

        int result;
        if (promptUser)
        {
            result = WNetUseConnection(IntPtr.Zero, nr, "", "", CONNECT_INTERACTIVE | CONNECT_PROMPT, null, null, null);
        }
        else
        {
            result = WNetUseConnection(IntPtr.Zero, nr, password, username, 0, null, null, null);
        }

        if (result != NO_ERROR)
        {
            throw new Win32Exception(result);
        }
    }

    private void DisconnectFromShare(string remoteUnc)
    {
        int result = WNetCancelConnection2(remoteUnc, CONNECT_UPDATE_PROFILE, false);
        if (result != NO_ERROR)
        {
            throw new Win32Exception(result);
        }
    }

    /// <summary>
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
    /// </summary>
    /// <filterpriority>2</filterpriority>
    public void Dispose()
    {
        this.DisconnectFromShare(this._remoteUncName);
    }
}

据我所知,你不需要 地图 UNC路到一个驱动的信,以便建立证书为一个服务器。我经常使用的批脚本,如:

net use \\myserver /user:username password

:: do something with \\myserver\the\file\i\want.xml

net use /delete \\my.server.com

然而,任何程序运行在相同的帐户你的程序仍然能够访问的一切 username:password 有权访问。一个可能的解决方案可能会隔离程序,在其自己的本地用户账户(UNC访问本地的帐户,该帐户被称为 NET USE).

注: 使用SMB跨领域不是很好使用的技术,海事组织。如果安全是重要的,事实上,SMB缺乏加密是一位器。

而不是WNetUseConnection,我建议 NetUseAdd.WNetUseConnection是一个传统功能,已经取代通过WNetUseConnection2和WNetUseConnection3,但是所有的这些功能创建一个网络设备可见,在Windows资源。NetUseAdd相当于呼吁净使用DOS证在远程计算机。

如果你打电话NetUseAdd后续试图访问的目录应该取得成功。

虽然我不知道我自己,我当然希望,#2,是不正确的,我想认为窗户是不会自动得到了我登录的信息(至少我所有的密码!) 任何机,让我们独自一个是不是我的一部分的信任。

无论如何,你有没有探讨的模拟结构?你的代码是要看起来类似这样的:

using (System.Security.Principal.WindowsImpersonationContext context = System.Security.Principal.WindowsIdentity.Impersonate(token))
{
    // Do network operations here

    context.Undo();
}

在这种情况下, token 变量是一个因此.为了获得值这一变,你就会打电话给非托管LogonUser Windows API功能。一个快速旅行 pinvoke.net 让我们以下的签名:

[System.Runtime.InteropServices.DllImport("advapi32.dll", SetLastError = true)]
public static extern bool LogonUser(
    string lpszUsername,
    string lpszDomain,
    string lpszPassword,
    int dwLogonType,
    int dwLogonProvider,
    out IntPtr phToken
);

用户名,域名和密码应该似乎相当明显。看一下各种价值观,可以传递给dwLogonType和dwLogonProvider确定一个最适合你的需要。

这个代码没有经过测试,因为我没有第二个领域,在这里我可以验证,但这应该希望把你放在正确的轨道。

最蔽的服务器支持SCP以及它可能很容易找到图书馆。你甚至可以叫一个现有客户的代码就像pscp包括与 腻子.

如果文件的类型你的工作是简单的东西就像一个文本或XML文件,你甚至可以去迄今为止为编写自己的客户/服务器实现操纵的文件使用类似的东西。网远程处理或网服务。

我已经看到备选方案3的实施与 JScape工具 在一个非常简单的方式。你可能会给它一试。它不是免费的,但是它不会成其工作。

这里最小的POC类w/所有令人讨厌的删除

using System;
using System.ComponentModel;
using System.Runtime.InteropServices;

public class UncShareWithCredentials : IDisposable
{
    private string _uncShare;

    public UncShareWithCredentials(string uncShare, string userName, string password)
    {
        var nr = new Native.NETRESOURCE
        {
            dwType = Native.RESOURCETYPE_DISK,
            lpRemoteName = uncShare
        };

        int result = Native.WNetUseConnection(IntPtr.Zero, nr, password, userName, 0, null, null, null);
        if (result != Native.NO_ERROR)
        {
            throw new Win32Exception(result);
        }
        _uncShare = uncShare;
    }

    public void Dispose()
    {
        if (!string.IsNullOrEmpty(_uncShare))
        {
            Native.WNetCancelConnection2(_uncShare, Native.CONNECT_UPDATE_PROFILE, false);
            _uncShare = null;
        }
    }

    private class Native
    {
        public const int RESOURCETYPE_DISK = 0x00000001;
        public const int CONNECT_UPDATE_PROFILE = 0x00000001;
        public const int NO_ERROR = 0;

        [DllImport("mpr.dll")]
        public static extern int WNetUseConnection(IntPtr hwndOwner, NETRESOURCE lpNetResource, string lpPassword, string lpUserID,
            int dwFlags, string lpAccessName, string lpBufferSize, string lpResult);

        [DllImport("mpr.dll")]
        public static extern int WNetCancelConnection2(string lpName, int dwFlags, bool fForce);

        [StructLayout(LayoutKind.Sequential)]
        public class NETRESOURCE
        {
            public int dwScope;
            public int dwType;
            public int dwDisplayType;
            public int dwUsage;
            public string lpLocalName;
            public string lpRemoteName;
            public string lpComment;
            public string lpProvider;
        }
    }
}

你可以直接使用 \\server\share\folder w/ WNetUseConnection, ,没有必要带它到 \\server 部分只有事先。

im附上我 vb.net 代码 基于上 布赖恩 参考

Imports System.ComponentModel

Imports System.Runtime.InteropServices

Public Class PinvokeWindowsNetworking

Const NO_ERROR As Integer = 0



Private Structure ErrorClass

    Public num As Integer

    Public message As String



    Public Sub New(ByVal num As Integer, ByVal message As String)

        Me.num = num

        Me.message = message

    End Sub

End Structure



Private Shared ERROR_LIST As ErrorClass() = New ErrorClass() {

    New ErrorClass(5, "Error: Access Denied"),

    New ErrorClass(85, "Error: Already Assigned"),

    New ErrorClass(1200, "Error: Bad Device"),

    New ErrorClass(67, "Error: Bad Net Name"),

    New ErrorClass(1204, "Error: Bad Provider"),

    New ErrorClass(1223, "Error: Cancelled"),

    New ErrorClass(1208, "Error: Extended Error"),

    New ErrorClass(487, "Error: Invalid Address"),

    New ErrorClass(87, "Error: Invalid Parameter"),

    New ErrorClass(1216, "Error: Invalid Password"),

    New ErrorClass(234, "Error: More Data"),

    New ErrorClass(259, "Error: No More Items"),

    New ErrorClass(1203, "Error: No Net Or Bad Path"),

    New ErrorClass(1222, "Error: No Network"),

    New ErrorClass(1206, "Error: Bad Profile"),

    New ErrorClass(1205, "Error: Cannot Open Profile"),

    New ErrorClass(2404, "Error: Device In Use"),

    New ErrorClass(2250, "Error: Not Connected"),

    New ErrorClass(2401, "Error: Open Files")}



Private Shared Function getErrorForNumber(ByVal errNum As Integer) As String

    For Each er As ErrorClass In ERROR_LIST

        If er.num = errNum Then Return er.message

    Next



    Try

        Throw New Win32Exception(errNum)

    Catch ex As Exception

        Return "Error: Unknown, " & errNum & " " & ex.Message

    End Try



    Return "Error: Unknown, " & errNum

End Function



<DllImport("Mpr.dll")>

Private Shared Function WNetUseConnection(ByVal hwndOwner As IntPtr, ByVal lpNetResource As NETRESOURCE, ByVal lpPassword As String, ByVal lpUserID As String, ByVal dwFlags As Integer, ByVal lpAccessName As String, ByVal lpBufferSize As String, ByVal lpResult As String) As Integer

End Function



<DllImport("Mpr.dll")>

Private Shared Function WNetCancelConnection2(ByVal lpName As String, ByVal dwFlags As Integer, ByVal fForce As Boolean) As Integer

End Function



<StructLayout(LayoutKind.Sequential)>

Private Class NETRESOURCE

    Public dwScope As Integer = 0

    Public dwType As Integer = 0

    Public dwDisplayType As Integer = 0

    Public dwUsage As Integer = 0

    Public lpLocalName As String = ""

    Public lpRemoteName As String = ""

    Public lpComment As String = ""

    Public lpProvider As String = ""

End Class



Public Shared Function connectToRemote(ByVal remoteUNC As String, ByVal username As String, ByVal password As String) As String

    Return connectToRemote(remoteUNC, username, password, False)

End Function



Public Shared Function connectToRemote(ByVal remoteUNC As String, ByVal username As String, ByVal password As String, ByVal promptUser As Boolean) As String

    Dim nr As NETRESOURCE = New NETRESOURCE()

    nr.dwType = ResourceTypes.Disk

    nr.lpRemoteName = remoteUNC

    Dim ret As Integer



    If promptUser Then

        ret = WNetUseConnection(IntPtr.Zero, nr, "", "", Connects.Interactive Or Connects.Prompt, Nothing, Nothing, Nothing)

    Else

        ret = WNetUseConnection(IntPtr.Zero, nr, password, username, 0, Nothing, Nothing, Nothing)

    End If



    If ret = NO_ERROR Then Return Nothing

    Return getErrorForNumber(ret)

End Function



Public Shared Function disconnectRemote(ByVal remoteUNC As String) As String

    Dim ret As Integer = WNetCancelConnection2(remoteUNC, Connects.UpdateProfile, False)

    If ret = NO_ERROR Then Return Nothing

    Return getErrorForNumber(ret)

End Function


Enum Resources As Integer

    Connected = &H1

    GlobalNet = &H2

    Remembered = &H3

End Enum


Enum ResourceTypes As Integer

    Any = &H0

    Disk = &H1

    Print = &H2

End Enum


Enum ResourceDisplayTypes As Integer

    Generic = &H0

    Domain = &H1

    Server = &H2

    Share = &H3

    File = &H4

    Group = &H5

End Enum


Enum ResourceUsages As Integer

    Connectable = &H1

    Container = &H2

End Enum


Enum Connects As Integer

    Interactive = &H8

    Prompt = &H10

    Redirect = &H80

    UpdateProfile = &H1

    CommandLine = &H800

    CmdSaveCred = &H1000

    LocalDrive = &H100

End Enum


End Class

如何使用它

Dim login = PinvokeWindowsNetworking.connectToRemote("\\ComputerName", "ComputerName\UserName", "Password")

    If IsNothing(login) Then



        'do your thing on the shared folder



       PinvokeWindowsNetworking.disconnectRemote("\\ComputerName")

    End If

我看了看MS找到答案。第一个解决办法假定的用户的账户运行的应用程序过程中已接到的共享文件夹或驱动(同样域)。确保你的DNS得到解决或者尝试利用IP地址。只需做到以下几点:

 DirectoryInfo di = new DirectoryInfo(PATH);
 var files = di.EnumerateFiles("*.*", SearchOption.AllDirectories);

如果你想在不同的领域。网2.0的凭证遵循这种模式:

WebRequest req = FileWebRequest.Create(new Uri(@"\\<server Name>\Dir\test.txt"));

        req.Credentials = new NetworkCredential(@"<Domain>\<User>", "<Password>");
        req.PreAuthenticate = true;

        WebResponse d = req.GetResponse();
        FileStream fs = File.Create("test.txt");

        // here you can check that the cast was successful if you want. 
        fs = d.GetResponseStream() as FileStream;
        fs.Close();
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top