Cara memberikan nama pengguna dan kata sandi saat menghubungkan ke jaringan berbagi

191

Saat menyambung ke jaringan berbagi yang untuknya pengguna saat ini (dalam kasus saya, pengguna layanan yang diaktifkan jaringan) tidak memiliki hak, nama dan kata sandi harus disediakan.

Saya tahu bagaimana melakukan ini dengan fungsi Win32 ( WNet*berasal dari keluarga mpr.dll), tetapi ingin melakukannya dengan fungsionalitas .Net (2.0).

Opsi apa yang tersedia?

Mungkin beberapa informasi membantu:

  • Case use adalah layanan windows, bukan aplikasi Asp.Net.
  • Layanan berjalan di bawah akun yang tidak memiliki hak untuk berbagi.
  • Akun pengguna yang dibutuhkan untuk pembagian tidak diketahui di sisi klien.
  • Klien dan server bukan anggota dari domain yang sama.
gyrolf
sumber
7
Meskipun saya tidak memberi Anda jawaban yang berguna, saya dapat memberikan anti-jawaban .. Peniruan identitas dan proses pemijahan karena Marc berpendapat tidak akan berfungsi ketika server dan klien tidak berada dalam domain yang sama, kecuali ada kepercayaan antara dua domain. Jika ada kepercayaan maka saya pikir itu akan berhasil. Saya hanya akan menjawab sebagai komentar untuk Marc tetapi saya tidak punya cukup perwakilan untuk berkomentar. : - /
Moose

Jawaban:

152

Anda dapat mengubah identitas utas, atau P / Invoke WNetAddConnection2. Saya lebih suka yang terakhir, karena kadang-kadang saya perlu mempertahankan beberapa kredensial untuk lokasi yang berbeda. Saya membungkusnya menjadi IDisposable dan memanggil WNetCancelConnection2 untuk menghapus kredit setelahnya (menghindari kesalahan beberapa nama pengguna):

using (new NetworkConnection(@"\\server\read", readCredentials))
using (new NetworkConnection(@"\\server2\write", writeCredentials)) {
   File.Copy(@"\\server\read\file", @"\\server2\write\file");
}
Mark Brackett
sumber
4
Layanan ini bukan anggota domain target - peniruan tidak dapat berfungsi karena Anda tidak akan dapat membuat token keamanan secara lokal dan menyamar sebagai peniru. PInvoke adalah satu - satunya cara.
stephbu
@ MarkBrackett Saya tahu ini adalah jawaban lama, tapi mungkin Anda masih tahu ... akankah akses diberikan hanya untuk program atau juga untuk pengguna yang masuk melalui penjelajah?
Breeze
@Breeze - Saya belum mengujinya, tapi saya harapkan otentikasi untuk sesi logon; jadi jika program Anda berjalan sebagai pengguna yang login, mereka akan memiliki akses juga (setidaknya selama durasi operasi).
Mark Brackett
8
Definisi readCredentials dan writeCredentials dapat dimasukkan dalam jawabannya.
Anders Lindén
2
Jika Anda mendapatkan Galat 53 , pastikan jalurnya tidak berakhir dengan "\"
Mustafa S.
327

Saya sangat menyukai jawaban Mark Brackett sehingga saya melakukan implementasi cepat saya sendiri. Ini dia jika ada orang lain yang membutuhkannya dengan tergesa-gesa:

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
}
Luke Quinane
sumber
10
Seharusnya begitu throw new Win32Exception(result);, karena WNetAddConnection2 mengembalikan kode kesalahan win32 ( ERROR_XXX)
torvin
2
Ini adalah bagian kecil dari kode yang brilian. Diperlukan untuk masuk ke sistem UNIX untuk mendapatkan daftar direktori untuk dicetak ke aplikasi web MVC5 dan ini berhasil. +1 !!!
Tay
3
Pernyataan penggunaan berikut diperlukan agar kode di atas dikompilasi: using System.Net; menggunakan System.Runtime.InteropServices; menggunakan System.ComponentModel;
Matt Nelson
4
maaf menyegarkan utas lama itu, tetapi sepertinya itu tidak menutup koneksi setelah blok selesai. Saya memiliki program untuk mengunggah beberapa gambar, yang pertama berjalan dengan baik, yang kedua memberi gagal. Koneksi dilepaskan ketika program ditutup. Adakah saran?
arti
3
Kami memiliki masalah yang sama dengan Anda, @arti. Dengan hanya mengatur nama pengguna dan kata sandi pada NetworkCredentialobjek aplikasi dapat terhubung satu kali ke drive jaringan. Setelah itu kami mendapat ERROR_LOGON_FAILURE pada setiap upaya hingga aplikasi dimulai ulang. Kami kemudian mencoba untuk memasok domain pada NetworkCredentialobjek juga, dan tiba-tiba berhasil! Saya tidak tahu mengapa ini memperbaiki masalah, terutama fakta bahwa itu berfungsi untuk terhubung sekali tanpa domain.
lsmeby
50

Hari ini 7 tahun kemudian saya menghadapi masalah yang sama dan saya ingin membagikan versi solusinya.

Sudah siap salin & tempel :-) Ini dia:

Langkah 1

Dalam kode Anda (setiap kali Anda perlu melakukan sesuatu dengan izin)

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

Langkah 2

File Helper yang melakukan sihir

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;
            }
        }
    }
}
Pavel Kovalev
sumber
2
@MohammadRashid Menurut dokumentasi pada LogonUser , ini hanya berfungsi untuk pengguna di komputer lokal: "Fungsi LogonUser mencoba untuk mencatat pengguna di komputer lokal. Komputer lokal adalah komputer dari mana LogonUser dipanggil. Anda tidak dapat menggunakan LogonUser untuk masuk ke komputer jarak jauh. "Anda akan menerima kesalahan" Win32Exception: Nama pengguna atau kata sandi salah. " Jadi saya kira mesin harus berada di domain yang sama setidaknya.
Charles Chen
1
@CharlesChen Baru membuktikan bahwa ini berfungsi dengan baik di seluruh domain, FYI. Server tempat saya menjalankan ini ada dalam DMZ, dan pasti terhubung ke server file pada domain yang berbeda, melalui firewall. Potongan pembunuh Pavel, kaulah orangnya, dan ini mungkin jawaban yang diterima hari ini.
Brian MacKay
Ini adalah SOLUSI YANG HEBAT! Terima kasih, Pavel Kovalev.
STLDev
apakah ini berfungsi pada ldap? ia mengatakan bahwa saya tidak memiliki server logon yang tersedia. saya menggunakan ldap auth
Julius Limson
28

Saya mencari banyak metode dan saya melakukannya dengan cara saya sendiri. Anda harus membuka koneksi antara dua mesin melalui command prompt perintah NET USE dan setelah menyelesaikan pekerjaan Anda menghapus koneksi dengan command prompt NET USE "myconnection" / delete.

Anda harus menggunakan proses Command Prompt dari kode di belakang seperti ini:

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

Penggunaannya sederhana:

SaveACopyfileToServer(filePath, savePath);

Berikut ini fungsinya:

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);
    }

Dan juga fungsi ExecuteCommand adalah:

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;
    } 

Fungsi ini bekerja sangat cepat dan stabil untuk saya.

Hakan KOSE
sumber
1
Jika pemetaan saham gagal, seperti apa kode pengembaliannya?
surega
14

Solusi Luke Quinane terlihat bagus, tetapi hanya berfungsi sebagian dalam aplikasi ASP.NET MVC saya. Memiliki dua saham di server yang sama dengan kredensial berbeda, saya bisa menggunakan peniruan hanya untuk yang pertama.

Masalah dengan WNetAddConnection2 juga berperilaku berbeda pada versi windows yang berbeda. Itu sebabnya saya mencari alternatif dan menemukan fungsi LogonUser . Berikut adalah kode saya yang juga berfungsi di 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;
    }
}

Pemakaian:

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

//do your stuff here

impersonationContext.Leave();
VladL
sumber
2
pendekatan ini bekerja dengan baik untuk saya, tetapi perhatikan dalam pengujian saya bahwa ketika menggunakan kata sandi yang buruk dengan akun pengguna domain, pengguna itu langsung membuang ke status terkunci. kebijakan domain kami meminta 3 upaya login yang gagal sebelum itu terjadi, tetapi melalui pendekatan ini satu upaya buruk dan Anda terkunci. Jadi, gunakan dengan hati-hati ...
kellyb
5

Untuk VB.lovers, VB.NET setara dengan kode Luke Quinane (terima kasih 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
Alessandro Bernardi
sumber
3

Salah satu opsi yang mungkin berfungsi adalah menggunakan WindowsIdentity.Impersonate(dan mengubah utas utas) untuk menjadi pengguna yang diinginkan, seperti itu . Kembali ke p / memohon, aku takut ...

Opsi nakal lainnya (dan sama-sama jauh dari ideal) mungkin untuk menelurkan proses untuk melakukan pekerjaan ... ProcessStartInfomenerima .UserName, .Passworddan .Domain.

Akhirnya - mungkin menjalankan layanan di akun khusus yang memiliki akses? (dihapus karena Anda telah mengklarifikasi bahwa ini bukan pilihan).

Marc Gravell
sumber
Saya tidak berpikir prosesnya adalah ide yang buruk. google mengeluarkan beberapa whitepaper tentang manfaat multiprosesing di chrome.
Dustin Getz
Apakah mungkin untuk mengubah pokok utas menjadi pengguna tanpa akun di mesin lokal?
gyrolf
Sejujurnya, saya tidak tahu ... Anda harus mencoba LogonUser dengan domain yang berbeda untuk mengetahuinya.
Marc Gravell
3

OKE ... Saya bisa resond ..

Penafian: Saya baru saja 18+ jam sehari (lagi) .. Saya sudah tua dan pelupa .. Saya tidak bisa mengeja .. Saya memiliki rentang perhatian yang pendek jadi saya lebih baik merespons dengan cepat .. :-)

Pertanyaan:

Apakah mungkin untuk mengubah pokok utas menjadi pengguna tanpa akun di mesin lokal?

Menjawab:

Ya, Anda dapat mengubah prinsip utas meskipun kredensial yang Anda gunakan tidak didefinisikan secara lokal atau di luar "hutan".

Saya baru saja mengalami masalah ini ketika mencoba terhubung ke server SQL dengan otentikasi NTLM dari layanan. Panggilan ini menggunakan kredensial yang terkait dengan proses yang berarti bahwa Anda memerlukan akun lokal atau akun domain untuk mengautentikasi sebelum Anda dapat berkedok sebagai. Blah, blah ...

Tapi...

Memanggil LogonUser (..) dengan atribut ???? _ NEW_CREDENTIALS akan mengembalikan token keamanan tanpa mencoba mengotentikasi kredensial. Kewl .. Tidak harus mendefinisikan akun di dalam "hutan". Setelah Anda memiliki token, Anda mungkin harus memanggil DuplicateToken () dengan opsi untuk mengaktifkan peniruan yang menghasilkan token baru. Sekarang panggil SetThreadToken (NULL, token); (Mungkin & token?) .. Panggilan ke ImpersonateLoggedonUser (token); mungkin diperlukan, tapi saya rasa tidak. Lihat itu ..

Lakukan apa yang perlu Anda lakukan ..

Panggil RevertToSelf () jika Anda memanggil ImpersonateLoggedonUser () lalu SetThreadToken (NULL, NULL); (Saya pikir ... lihat itu), dan kemudian CloseHandle () pada gagang yang dibuat ..

Tidak ada janji tapi ini berhasil untuk saya ... Ini di atas kepala saya (seperti rambut saya) dan saya tidak bisa mengeja !!!

Craig Armstrong
sumber
1

Juga porting ke F # untuk digunakan dengan 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
python_kaa
sumber
0

Anda harus melihat menambahkan seperti ini:

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

Ke dalam web.config Anda.

Informasi Lebih Lanjut.

GEOCHET
sumber
Beberapa Keamanan Korporat mencegah penggunaan peniruan identitas karena mereka tidak dapat melacak aplikasi yang menggunakannya dan harus menggunakan domain yang sama atau tepercaya. Saya pikir dukungan palsu terlihat. Akun layanan domain dengan pinvoke tampaknya merupakan cara yang tepat.
Jim