네트워크 공유에 연결할 때 사용자 이름과 비밀번호를 제공하는 방법


191

현재 사용자 (필자의 경우 네트워크 가능 서비스 사용자)가없는 네트워크 공유에 연결할 때 이름, 암호를 제공해야합니다.

Win32 기능 (의 WNet*제품군 mpr.dll) 으로이 작업을 수행하는 방법을 알고 있지만 .Net (2.0) 기능으로 수행하고 싶습니다.

어떤 옵션을 사용할 수 있습니까?

더 많은 정보가 도움이 될 수 있습니다.

  • 유스 케이스는 Asp.Net 애플리케이션이 아닌 Windows 서비스입니다.
  • 공유에 대한 권한이없는 계정으로 서비스가 실행되고 있습니다.
  • 공유에 필요한 사용자 계정은 클라이언트 측에 알려지지 않았습니다.
  • 클라이언트와 서버가 같은 도메인의 구성원이 아닙니다.

7
유용한 답변을 제공하지는 않지만 반 답변을 제공 할 수 있습니다. 서버와 클라이언트가 동일한 도메인에 있지 않은 경우 Marc가 배치 한 것처럼 가장 및 프로세스 생성은 작동하지 않습니다. 두 도메인. 신뢰가 있다면 효과가 있다고 생각합니다. Marc 's에 대한 의견으로 방금 답장을했지만 의견을 제시 할 충분한 답변이 없습니다. :-/
Moose

답변:


152

스레드 ID를 변경하거나 P / Invoke WNetAddConnection2를 지정할 수 있습니다. 때로는 다른 위치에 대해 여러 자격 증명을 유지해야하기 때문에 후자를 선호합니다. IDisposable에 래핑하고 WNetCancelConnection2를 호출하여 이후에 cred를 제거합니다 (여러 사용자 이름 오류 방지).

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

@Breeze-테스트하지는 않았지만 로그온 세션에 대해 인증 될 것으로 예상합니다. 따라서 프로그램이 로그온 한 사용자로 실행중인 경우 (적어도 작업 기간 동안) 액세스 할 수 있습니다.
Mark Brackett

8
readCredentials 및 writeCredentials의 정의가 답변에 포함될 수 있습니다.
Anders Lindén

2
당신이 얻는 경우 오류 (53) , 확인 경로가 "\"로 끝나는 있지 않은지 확인
무스타파 S.

327

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
이것은 훌륭하고 작은 코드입니다. MVC5 웹 응용 프로그램으로 인쇄하기위한 디렉토리 목록을 가져 오기 위해 UNIX 시스템에 로그온해야했으며이 방법을 사용했습니다. +1 !!!
Tay

3
위의 코드를 컴파일하려면 다음 using 문이 필요합니다. using System.Net; System.Runtime.InteropServices 사용; System.ComponentModel 사용;
Matt Nelson

4
오래된 스레드를 새로 고쳐서 죄송하지만 블록이 끝난 후에도 연결이 닫히지 않는 것 같습니다. 나는 몇 장의 사진을 업로드하는 프로그램을 가지고 있습니다. 첫 번째 사진은 잘 가고 두 번째 사진은 실패합니다. 프로그램이 닫히면 연결이 해제됩니다. 조언이 있습니까?
arti

3
우리는 @arti와 같은 문제를 겪었습니다. NetworkCredential개체 에서 사용자 이름과 암호를 설정하면 응용 프로그램이 네트워크 드라이브에 한 번 연결할 수있었습니다. 그 후 응용 프로그램이 다시 시작될 때까지 각 시도마다 ERROR_LOGON_FAILURE 가 발생했습니다 . 그런 다음 NetworkCredential객체에 도메인을 제공하려고 시도했지만 갑자기 작동했습니다! 왜 이것이 문제를 해결했는지, 특히 도메인없이 한 번 연결하면 효과가 있다는 것을 모릅니다.
lsmeby

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 : 사용자 이름 또는 암호가 잘못되었습니다. "라는 오류 메시지가 나타납니다. 따라서 머신이 최소한 동일한 도메인에 있어야한다고 가정합니다.
Charles Chen

1
@CharlesChen 그냥 도메인 전체에서 잘 작동 함을 증명했습니다. 내가 실행중인 서버는 DMZ에 있으며 방화벽을 통해 다른 도메인의 파일 서버에 확실히 연결되어 있습니다. 킬러 스 니펫 파벨, 당신은 남자이고, 이것은 아마도 오늘날 받아 들일만한 대답 일 것입니다.
Brian MacKay

이것은 위대한 솔루션입니다! 감사합니다, Pavel Kovalev.
STLDev

이것이 ldap에서 작동합니까? 사용 가능한 로그온 서버가 없다고 말합니다. LDAP의 인증을 사용하여 메신저
줄리어스 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
이 방법은 저에게 효과적이지만 도메인 테스트에서 잘못된 암호를 사용하면 해당 사용자는 즉시 잠금 상태가됩니다. Google 도메인 정책은 그 전에 3 번의 실패한 로그인 시도를 요청하지만이 방법을 통해 한 번의 잘못된 시도로 잠긴 상태입니다. 따라서주의해서 사용하십시오.
kellyb

5

VB.lovers의 경우 Luke Quinane 코드와 동등한 VB.NET (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로 돌아가서 두렵습니다.

또 건방진 (와 동등하게 멀리 이상적에서) 옵션은 ... 일을 할 수있는 프로세스를 생성 할 수 있습니다 ProcessStartInfoA가 받아 .UserName, .Password.Domain.

마지막으로-액세스 권한이있는 전용 계정으로 서비스를 실행 하시겠습니까? (이것은 옵션이 아님을 명확히 한대로 제거되었습니다).


나는 프로세스가 그렇게 나쁜 생각이라고 생각하지 않습니다. 구글은 크롬에서 멀티 프로세싱의 이점에 대한 백서를 발표했다.
더스틴 겟츠

로컬 시스템에 계정이없는 사용자로 스레드 프린시 펄을 변경할 수 있습니까?
자이 로프

솔직히 말해서, 나는 단순히 모른다 ... 당신은 알아 내기 위해 다른 도메인으로 LogonUser를 시도해야 할 것이다.
Marc Gravell

3

알았어 .. 공감할 수있어

면책 조항 : 나는 단지 18 시간 동안 하루를 보냈습니다 .. 나는 나이가 들었고 잊어 버렸습니다.

질문:

로컬 시스템에 계정이없는 사용자로 스레드 프린시 펄을 변경할 수 있습니까?

대답:

예. 사용중인 자격 증명이 로컬로 정의되어 있지 않거나 "포리스트"외부에있는 경우에도 스레드 주체를 변경할 수 있습니다.

서비스에서 NTLM 인증을 사용하여 SQL Server에 연결하려고 할 때이 문제가 발생했습니다. 이 호출은 프로세스와 관련된 자격 증명을 사용하여 가장하기 전에 인증하기 위해 로컬 계정 또는 도메인 계정이 필요하다는 것을 의미합니다. 이러쿵 저러쿵...

그러나...

???? _ NEW_CREDENTIALS 속성으로 LogonUser (..)를 호출하면 자격 증명을 인증하지 않고 보안 토큰을 반환합니다. Kewl .. "숲"내에서 계정을 정의 할 필요가 없습니다. 토큰이 있으면 가장을 활성화하여 새 토큰을 생성하는 옵션과 함께 DuplicateToken ()을 호출해야 할 수도 있습니다. 이제 SetThreadToken (NULL, token)을 호출하십시오. (& token? 일 수 있습니다.). ImpersonateLoggedonUser (token)에 대한 호출; 필요할 수도 있지만 그렇게 생각하지 않습니다. 찾아 봐 ..

해야 할 일을하십시오 ..

ImpersonateLoggedonUser ()를 호출 한 경우 RevertToSelf ()를 호출 한 다음 SetThreadToken (NULL, NULL); (제 생각에는 ... 찾아보십시오)를 만든 다음 생성 된 핸들에서 CloseHandle () ..

약속은 없지만 이것은 나를 위해 일했습니다 ... 이것은 내 머리 꼭대기에서 떨어져 있으며 (내 머리카락처럼) 철자가 없습니다!



1

FAKE 와 함께 사용 하기 위해 F # 으로 포팅

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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.