连接到网络共享时如何提供用户名和密码


191

当连接到当前用户(在我的情况下,是启用网络的服务用户)没有权限的网络共享时,必须提供名称和密码。

我知道如何使用Win32函数(WNet*来自的家族mpr.dll)来执行此操作,但想使用.Net(2.0)功能来执行此操作。

有哪些选项可用?

也许更多信息可以帮助您:

  • 用例是Windows服务,而不是Asp.Net应用程序。
  • 该服务在没有共享权限的帐户下运行。
  • 共享所需的用户帐户在客户端未知。
  • 客户端和服务器不是同一域的成员。

7
虽然我没有为您提供有用的答案,但是我可以提供一个反答案。当服务器和客户端不在同一域中时,模拟和生成Marc假定的过程将无法正常工作,除非在彼此之间建立信任关系这两个域。如果有信任,那么我认为它将起作用。我只是对Marc's的评论做出了回应,但我没有足够的代表对此发表评论。:-/
Moose

Answers:


152

您可以更改线程标识,或P /调用WNetAddConnection2。我更喜欢后者,因为有时我需要为不同的位置维护多个凭据。我将其包装到IDisposable中,然后调用WNetCancelConnection2以删除凭据(避免出现多个用户名错误):

using (new NetworkConnection(@"\\server\read", readCredentials))
using (new NetworkConnection(@"\\server2\write", writeCredentials)) {
   File.Copy(@"\\server\read\file", @"\\server2\write\file");
}

4
该服务不是目标域的成员-模拟无法正常工作,因为您将无法在本地创建安全令牌并对其进行模拟。PInvoke是唯一的方法。
stephbu

@MarkBrackett我知道这是一个旧答案,但是也许您仍然知道...该访问权限将仅授予该程序还是通过资源管理器授予登录用户?
微风

@Breeze-我尚未测试过,但是我希望它在登录会话时进行身份验证;因此,如果您的程序以登录用户身份运行,那么他们也将具有访问权限(至少在操作期间)。
Mark Brackett

8
答案中可以包含readCredentials和writeCredentials的定义。
安德斯·林登

2
如果您遇到错误53,请确保路径未以“ \”结尾
Mustafa

326

我非常喜欢Mark Brackett的回答,因此我自己进行了快速实施。如果有人急需,这里就是这样:

public class NetworkConnection : IDisposable
{
    string _networkName;

    public NetworkConnection(string networkName, 
        NetworkCredential credentials)
    {
        _networkName = networkName;

        var netResource = new NetResource()
        {
            Scope = ResourceScope.GlobalNetwork,
            ResourceType = ResourceType.Disk,
            DisplayType = ResourceDisplaytype.Share,
            RemoteName = networkName
        };

        var userName = string.IsNullOrEmpty(credentials.Domain)
            ? credentials.UserName
            : string.Format(@"{0}\{1}", credentials.Domain, credentials.UserName);

        var result = WNetAddConnection2(
            netResource, 
            credentials.Password,
            userName,
            0);

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

    ~NetworkConnection()
    {
        Dispose(false);
    }

    public void Dispose()
    {
        Dispose(true);
        GC.SuppressFinalize(this);
    }

    protected virtual void Dispose(bool disposing)
    {
        WNetCancelConnection2(_networkName, 0, true);
    }

    [DllImport("mpr.dll")]
    private static extern int WNetAddConnection2(NetResource netResource, 
        string password, string username, int flags);

    [DllImport("mpr.dll")]
    private static extern int WNetCancelConnection2(string name, int flags,
        bool force);
}

[StructLayout(LayoutKind.Sequential)]
public class NetResource
{
    public ResourceScope Scope;
    public ResourceType ResourceType;
    public ResourceDisplaytype DisplayType;
    public int Usage;
    public string LocalName;
    public string RemoteName;
    public string Comment;
    public string Provider;
}

public enum ResourceScope : int
{
    Connected = 1,
    GlobalNetwork,
    Remembered,
    Recent,
    Context
};

public enum ResourceType : int
{
    Any = 0,
    Disk = 1,
    Print = 2,
    Reserved = 8,
}

public enum ResourceDisplaytype : int
{
    Generic = 0x0,
    Domain = 0x01,
    Server = 0x02,
    Share = 0x03,
    File = 0x04,
    Group = 0x05,
    Network = 0x06,
    Root = 0x07,
    Shareadmin = 0x08,
    Directory = 0x09,
    Tree = 0x0a,
    Ndscontainer = 0x0b
}

10
确实应该这样throw new Win32Exception(result);,因为WNetAddConnection2返回win32错误代码(ERROR_XXX
torvin

2
这是一段精彩的代码。需要登录到UNIX系统以获得用于打印到MVC5 Web应用程序的目录列表,这确实可以解决问题。+1 !!!
2014年

3
为了使上面的代码编译,需要以下using语句:using System.Net; 使用System.Runtime.InteropServices; 使用System.ComponentModel;
马特·尼尔森

4
很抱歉,刷新该旧线程,但看起来在块完成后它没有关闭连接。我有一个程序可以上传少量图片,第一个可以正常运行,第二个可以失败。程序关闭时,连接被释放。有什么建议吗?
arti

3
@arti和您有同样的问题。通过仅在NetworkCredential对象上设置用户名和密码,应用程序就可以一次连接到网络驱动器。之后,每次尝试都会得到ERROR_LOGON_FAILURE,直到重新启动应用程序。然后,我们也尝试在NetworkCredential对象上提供域,然后突然起作用了!我不知道为什么这可以解决问题,尤其是事实证明它可以在没有域的情况下连接一次。
lsmeby '16

50

7年后的今天,我面临着同样的问题,我想分享我的解决方案版本。

它已经准备好复制和粘贴了:-)这是:

第1步

在您的代码中(无论何时需要执行权限操作)

ImpersonationHelper.Impersonate(domain, userName, userPassword, delegate
                            {
                                //Your code here 
                                //Let's say file copy:
                                if (!File.Exists(to))
                                {
                                    File.Copy(from, to);
                                }
                            });

第2步

魔术的助手文件

using System;
using System.Runtime.ConstrainedExecution;
using System.Runtime.InteropServices;
using System.Security;
using System.Security.Permissions;
using System.Security.Principal;    
using Microsoft.Win32.SafeHandles;


namespace BlaBla
{
    public sealed class SafeTokenHandle : SafeHandleZeroOrMinusOneIsInvalid
    {
        private SafeTokenHandle()
            : base(true)
        {
        }

        [DllImport("kernel32.dll")]
        [ReliabilityContract(Consistency.WillNotCorruptState, Cer.Success)]
        [SuppressUnmanagedCodeSecurity]
        [return: MarshalAs(UnmanagedType.Bool)]
        private static extern bool CloseHandle(IntPtr handle);

        protected override bool ReleaseHandle()
        {
            return CloseHandle(handle);
        }
    }

    public class ImpersonationHelper
    {
        [DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
        private static extern bool LogonUser(String lpszUsername, String lpszDomain, String lpszPassword,
        int dwLogonType, int dwLogonProvider, out SafeTokenHandle phToken);

        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]
        private extern static bool CloseHandle(IntPtr handle);

        [PermissionSet(SecurityAction.Demand, Name = "FullTrust")]
        public static void Impersonate(string domainName, string userName, string userPassword, Action actionToExecute)
        {
            SafeTokenHandle safeTokenHandle;
            try
            {

                const int LOGON32_PROVIDER_DEFAULT = 0;
                //This parameter causes LogonUser to create a primary token.
                const int LOGON32_LOGON_INTERACTIVE = 2;

                // Call LogonUser to obtain a handle to an access token.
                bool returnValue = LogonUser(userName, domainName, userPassword,
                    LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
                    out safeTokenHandle);
                //Facade.Instance.Trace("LogonUser called.");

                if (returnValue == false)
                {
                    int ret = Marshal.GetLastWin32Error();
                    //Facade.Instance.Trace($"LogonUser failed with error code : {ret}");

                    throw new System.ComponentModel.Win32Exception(ret);
                }

                using (safeTokenHandle)
                {
                    //Facade.Instance.Trace($"Value of Windows NT token: {safeTokenHandle}");
                    //Facade.Instance.Trace($"Before impersonation: {WindowsIdentity.GetCurrent().Name}");

                    // Use the token handle returned by LogonUser.
                    using (WindowsIdentity newId = new WindowsIdentity(safeTokenHandle.DangerousGetHandle()))
                    {
                        using (WindowsImpersonationContext impersonatedUser = newId.Impersonate())
                        {
                            //Facade.Instance.Trace($"After impersonation: {WindowsIdentity.GetCurrent().Name}");
                            //Facade.Instance.Trace("Start executing an action");

                            actionToExecute();

                            //Facade.Instance.Trace("Finished executing an action");
                        }
                    }
                    //Facade.Instance.Trace($"After closing the context: {WindowsIdentity.GetCurrent().Name}");
                }

            }
            catch (Exception ex)
            {
                //Facade.Instance.Trace("Oh no! Impersonate method failed.");
                //ex.HandleException();
                //On purpose: we want to notify a caller about the issue /Pavel Kovalev 9/16/2016 2:15:23 PM)/
                throw;
            }
        }
    }
}

2
@MohammadRashid根据LogonUser的文档,它仅适用于本地计算机上的用户:“ LogonUser函数试图将用户登录到本地计算机。本地计算机是调用LogonUser的计算机。您不能使用LogonUser登录到远程计算机。“您将收到错误” Win32Exception:用户名或密码不正确。“ 因此,我认为计算机至少需要位于同一域中。
陈晨

1
@CharlesChen刚刚证明,跨域,FYI可以正常工作。我正在其上运行的服务器位于DMZ中,并且肯定通过防火墙连接到其他域上的文件服务器。杀手摘要Pavel,您是男人,今天应该应该是公认的答案。
布赖恩·麦凯

这是一个很好的解决方案!谢谢帕维尔·科瓦列夫(Pavel Kovalev)。
STLDev

这对ldap有用吗?它说我没有可用的登录服务器。即时通讯使用ldap auth
Julius Limson,

28

我搜索了很多方法,并且以自己的方式做到了。您必须通过命令提示符NET USE命令打开两台计算机之间的连接,并在完成工作后使用命令提示符NET USE“ myconnection” / delete清除连接。

您必须像下面这样从后面的代码中使用命令提示符过程:

var savePath = @"\\servername\foldername\myfilename.jpg";
var filePath = @"C:\\temp\myfileTosave.jpg";

用法很简单:

SaveACopyfileToServer(filePath, savePath);

功能如下:

using System.IO
using System.Diagnostics;


public static void SaveACopyfileToServer(string filePath, string savePath)
    {
        var directory = Path.GetDirectoryName(savePath).Trim();
        var username = "loginusername";
        var password = "loginpassword";
        var filenameToSave = Path.GetFileName(savePath);

        if (!directory.EndsWith("\\"))
            filenameToSave = "\\" + filenameToSave;

        var command = "NET USE " + directory + " /delete";
        ExecuteCommand(command, 5000);

        command = "NET USE " + directory + " /user:" + username + " " + password;
        ExecuteCommand(command, 5000);

        command = " copy \"" + filePath + "\"  \"" + directory + filenameToSave + "\"";

        ExecuteCommand(command, 5000);


        command = "NET USE " + directory + " /delete";
        ExecuteCommand(command, 5000);
    }

而且ExecuteCommand函数是:

public static int ExecuteCommand(string command, int timeout)
    {
        var processInfo = new ProcessStartInfo("cmd.exe", "/C " + command)
                              {
                                  CreateNoWindow = true, 
                                  UseShellExecute = false, 
                                  WorkingDirectory = "C:\\",
                              };

        var process = Process.Start(processInfo);
        process.WaitForExit(timeout);
        var exitCode = process.ExitCode;
        process.Close();
        return exitCode;
    } 

此功能对我来说非常快速且稳定。


1
万一份额映射失败,返回码是什么?
surega

14

Luke Quinane解决方案看起来不错,但在我的ASP.NET MVC应用程序中仅能部分工作。在同一台服务器上有两个共享且使用不同的凭据,我只能对第一个使用模拟。

WNetAddConnection2的问题还在于,它在不同的Windows版本上的行为不同。这就是为什么我寻找替代方法并找到LogonUser函数的原因。这是我的代码,也可以在ASP.NET中使用:

public sealed class WrappedImpersonationContext
{
    public enum LogonType : int
    {
        Interactive = 2,
        Network = 3,
        Batch = 4,
        Service = 5,
        Unlock = 7,
        NetworkClearText = 8,
        NewCredentials = 9
    }

    public enum LogonProvider : int
    {
        Default = 0,  // LOGON32_PROVIDER_DEFAULT
        WinNT35 = 1,
        WinNT40 = 2,  // Use the NTLM logon provider.
        WinNT50 = 3   // Use the negotiate logon provider.
    }

    [DllImport("advapi32.dll", EntryPoint = "LogonUserW", SetLastError = true, CharSet = CharSet.Unicode)]
    public static extern bool LogonUser(String lpszUsername, String lpszDomain,
        String lpszPassword, LogonType dwLogonType, LogonProvider dwLogonProvider, ref IntPtr phToken);

    [DllImport("kernel32.dll")]
    public extern static bool CloseHandle(IntPtr handle);

    private string _domain, _password, _username;
    private IntPtr _token;
    private WindowsImpersonationContext _context;

    private bool IsInContext
    {
        get { return _context != null; }
    }

    public WrappedImpersonationContext(string domain, string username, string password)
    {
        _domain = String.IsNullOrEmpty(domain) ? "." : domain;
        _username = username;
        _password = password;
    }

    // Changes the Windows identity of this thread. Make sure to always call Leave() at the end.
    [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
    public void Enter()
    {
        if (IsInContext)
            return;

        _token = IntPtr.Zero;
        bool logonSuccessfull = LogonUser(_username, _domain, _password, LogonType.NewCredentials, LogonProvider.WinNT50, ref _token);
        if (!logonSuccessfull)
        {
            throw new Win32Exception(Marshal.GetLastWin32Error());
        }
        WindowsIdentity identity = new WindowsIdentity(_token);
        _context = identity.Impersonate();

        Debug.WriteLine(WindowsIdentity.GetCurrent().Name);
    }

    [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
    public void Leave()
    {
        if (!IsInContext)
            return;

        _context.Undo();

        if (_token != IntPtr.Zero)
        {
            CloseHandle(_token);
        }
        _context = null;
    }
}

用法:

var impersonationContext = new WrappedImpersonationContext(Domain, Username, Password);
impersonationContext.Enter();

//do your stuff here

impersonationContext.Leave();

2
这种方法对我来说效果很好,但是在我的测试中注意到,当对域用户帐户使用错误的密码时,该用户将立即进入锁定状态。我们的域策略要求在此之前发生3次失败的登录尝试,但是通过这种方法,一次错误的尝试就将您锁定了。因此,请谨慎使用...
kellyb,2015年

5

对于VB.lovers来说,VB.NET相当于Luke Quinane的代码(感谢Luke!)。

Imports System
Imports System.Net
Imports System.Runtime.InteropServices
Imports System.ComponentModel

Public Class NetworkConnection
    Implements IDisposable

    Private _networkName As String

    Public Sub New(networkName As String, credentials As NetworkCredential)
        _networkName = networkName

        Dim netResource = New NetResource() With {
             .Scope = ResourceScope.GlobalNetwork,
             .ResourceType = ResourceType.Disk,
             .DisplayType = ResourceDisplaytype.Share,
             .RemoteName = networkName
        }

        Dim userName = If(String.IsNullOrEmpty(credentials.Domain), credentials.UserName, String.Format("{0}\{1}", credentials.Domain, credentials.UserName))

        Dim result = WNetAddConnection2(NetResource, credentials.Password, userName, 0)

        If result <> 0 Then
            Throw New Win32Exception(result, "Error connecting to remote share")
        End If
    End Sub

    Protected Overrides Sub Finalize()
        Try
            Dispose (False)
        Finally
            MyBase.Finalize()
        End Try
    End Sub

    Public Sub Dispose() Implements IDisposable.Dispose
        Dispose (True)
        GC.SuppressFinalize (Me)
    End Sub

    Protected Overridable Sub Dispose(disposing As Boolean)
        WNetCancelConnection2(_networkName, 0, True)
    End Sub

    <DllImport("mpr.dll")> _
    Private Shared Function WNetAddConnection2(netResource As NetResource, password As String, username As String, flags As Integer) As Integer
    End Function

    <DllImport("mpr.dll")> _
    Private Shared Function WNetCancelConnection2(name As String, flags As Integer, force As Boolean) As Integer
    End Function

End Class

<StructLayout(LayoutKind.Sequential)> _
Public Class NetResource
    Public Scope As ResourceScope
    Public ResourceType As ResourceType
    Public DisplayType As ResourceDisplaytype
    Public Usage As Integer
    Public LocalName As String
    Public RemoteName As String
    Public Comment As String
    Public Provider As String
End Class

Public Enum ResourceScope As Integer
    Connected = 1
    GlobalNetwork
    Remembered
    Recent
    Context
End Enum

Public Enum ResourceType As Integer
    Any = 0
    Disk = 1
    Print = 2
    Reserved = 8
End Enum

Public Enum ResourceDisplaytype As Integer
    Generic = &H0
    Domain = &H1
    Server = &H2
    Share = &H3
    File = &H4
    Group = &H5
    Network = &H6
    Root = &H7
    Shareadmin = &H8
    Directory = &H9
    Tree = &HA
    Ndscontainer = &HB
End Enum

3

可能可行的一种选择是使用WindowsIdentity.Impersonate(并更改线程主体)成为所需的用户,例如。回到p / invoke,不过,恐怕...

另一个厚颜无耻(同样不理想)的选择可能是产生一个流程来完成工作... ProcessStartInfo接受一个.UserName.Password然后.Domain

最后-也许在具有访问权限的专用帐户中运行服务?(已删除,因为您已确认这不是一种选择)。


我不认为处理程序是一个坏主意。谷歌发布了一些有关chrome多重处理的好处的白皮书。
达斯汀·盖茨

是否可以将线程主体更改为在本地计算机上没有帐户的用户?
gyrolf

老实说,我只是不知道...您必须尝试使用​​其他域的LogonUser来查找。
马克·格雷夫

3

好...我可以回应

免责声明:(我再次)每天有18个多小时的工作..我又老又忘了..我不会拼写..我的注意力不集中,所以我最好快速做出反应.. :-)

题:

是否可以将线程主体更改为在本地计算机上没有帐户的用户?

回答:

是的,即使您使用的凭据未在本地定义或不在“林”中,也可以更改线程主体。

尝试从服务通过NTLM身份验证连接到SQL Server时,我只是遇到了此问题。该调用使用与该过程关联的凭据,这意味着您需要本地帐户或域帐户进行身份验证才能进行模拟。等等,等等

但...

调用属性为???? _ NEW_CREDENTIALS的LogonUser(..)将返回安全令牌,而无需尝试对凭据进行身份验证。Kewl ..不必在“森林”中定义帐户。获得令牌后,您可能必须调用DuplicateToken(),并选择启用模拟以生成新令牌。现在调用SetThreadToken(NULL,token); (可能是&token?)。调用ImpersonateLoggedonUser(token); 可能是必需的,但我不这么认为。查一下..

做你需要做的..

如果调用了ImpersonateLoggedonUser(),则调用RevertToSelf(),然后调用SetThreadToken(NULL,NULL); (我认为...查找),然后在创建的句柄上使用CloseHandle()。

没有承诺,但这对我有用...这不在我的头顶上(像我的头发),我无法拼写!!!



1

也移植到F#以与FAKE一起使用

module NetworkShare

open System
open System.ComponentModel
open System.IO
open System.Net
open System.Runtime.InteropServices

type ResourceScope =
| Connected = 1
| GlobalNetwork = 2
| Remembered = 3
| Recent = 4
type ResourceType =
| Any = 0
| Disk = 1
| Print = 2
| Reserved = 8
type ResourceDisplayType =
| Generic = 0x0
| Domain = 0x01
| Server = 0x02
| Share = 0x03
| File = 0x04
| Group = 0x05
| Network = 0x06
| Root = 0x07
| Shareadmin = 0x08
| Directory = 0x09
| Tree = 0x0a
| Ndscontainer = 0x0b

//Uses of this construct may result in the generation of unverifiable .NET IL code.
#nowarn "9"
[<StructLayout(LayoutKind.Sequential)>]
type NetResource =
  struct
    val mutable Scope : ResourceScope
    val mutable ResourceType : ResourceType
    val mutable DisplayType : ResourceDisplayType
    val mutable Usage : int
    val mutable LocalName : string
    val mutable RemoteName : string
    val mutable Comment : string
    val mutable Provider : string
    new(name) = {
      // lets preset needed fields
      NetResource.Scope = ResourceScope.GlobalNetwork
      ResourceType = ResourceType.Disk
      DisplayType = ResourceDisplayType.Share
      Usage = 0
      LocalName = null
      RemoteName = name
      Comment = null
      Provider = null
    }
  end

type WNetConnection(networkName : string, credential : NetworkCredential) =
  [<Literal>]
  static let Mpr = "mpr.dll"
  [<DllImport(Mpr, EntryPoint = "WNetAddConnection2")>]
  static extern int connect(NetResource netResource, string password, string username, int flags)
  [<DllImport(Mpr, EntryPoint = "WNetCancelConnection2")>]
  static extern int disconnect(string name, int flags, bool force)

  let mutable disposed = false;

  do
    let userName = if String.IsNullOrWhiteSpace credential.Domain
                   then credential.UserName
                   else credential.Domain + "\\" + credential.UserName
    let resource = new NetResource(networkName)

    let result = connect(resource, credential.Password, userName, 0)

    if result <> 0 then
      let msg = "Error connecting to remote share " + networkName
      new Win32Exception(result, msg)
      |> raise

  let cleanup(disposing:bool) =
    if not disposed then
      disposed <- true
      if disposing then () // TODO dispose managed resources here
      disconnect(networkName, 0, true) |> ignore

  interface IDisposable with
    member __.Dispose() =
      disconnect(networkName, 0, true) |> ignore
      GC.SuppressFinalize(__)

  override __.Finalize() = cleanup(false)

type CopyPath =
  | RemotePath of string * NetworkCredential
  | LocalPath of string

let createDisposable() =
  {
    new IDisposable with
      member __.Dispose() = ()
  }

let copyFile overwrite destPath srcPath : unit =
  use _srcConn =
    match srcPath with
    | RemotePath(path, credential) -> new WNetConnection(path, credential) :> IDisposable
    | LocalPath(_) -> createDisposable()
  use _destConn =
    match destPath with
    | RemotePath(path, credential) -> new WNetConnection(path, credential) :> IDisposable
    | LocalPath(_) -> createDisposable()
  match srcPath, destPath with
  | RemotePath(src, _), RemotePath(dest, _)
  | LocalPath(src), RemotePath(dest, _)
  | RemotePath(src, _), LocalPath(dest)
  | LocalPath(src), LocalPath(dest) ->
    if FileInfo(src).Exists |> not then
      failwith ("Source file not found: " + src)
    let destFilePath =
      if DirectoryInfo(dest).Exists then Path.Combine(dest, Path.GetFileName src)
      else dest
    File.Copy(src, destFilePath, overwrite)

let rec copyDir copySubDirs filePattern destPath srcPath =
  use _srcConn =
    match srcPath with
    | RemotePath(path, credential) -> new WNetConnection(path, credential) :> IDisposable
    | LocalPath(_) -> createDisposable()
  use _destConn =
    match destPath with
    | RemotePath(path, credential) -> new WNetConnection(path, credential) :> IDisposable
    | LocalPath(_) -> createDisposable()
  match srcPath, destPath with
  | RemotePath(src, _), RemotePath(dest, _)
  | LocalPath(src), RemotePath(dest, _)
  | RemotePath(src, _), LocalPath(dest)
  | LocalPath(src), LocalPath(dest) ->
    let dir = DirectoryInfo(src)
    if dir.Exists |> not then
      failwith ("Source directory not found: " + src)

    let dirs = dir.GetDirectories()
    if Directory.Exists(dest) |> not then
      Directory.CreateDirectory(dest) |> ignore

    let files = dir.GetFiles(filePattern)
    for file in files do
      let tempPath = Path.Combine(dest, file.Name)
      file.CopyTo(tempPath, false) |> ignore

    if copySubDirs then
      for subdir in dirs do
        let subdirSrc =
          match srcPath with
          | RemotePath(_, credential) -> RemotePath(Path.Combine(dest, subdir.Name), credential)
          | LocalPath(_) -> LocalPath(Path.Combine(dest, subdir.Name))
        let subdirDest =
          match destPath with
          | RemotePath(_, credential) -> RemotePath(subdir.FullName, credential)
          | LocalPath(_) -> LocalPath(subdir.FullName)
        copyDir copySubDirs filePattern subdirDest subdirSrc

0

您应该在添加这样的内容:

<identity impersonate="true" userName="domain\user" password="****" />

进入您的web.config。

更多信息。


某些公司安全性阻止使用模拟,因为它们无法跟踪使用它的应用程序,并且必须在相同或受信任的域中。我认为可以找到个性化的支持。使用pinvoke的域服务帐户似乎是可行的方法。
吉姆(Jim)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.