Come fornire nome utente e password durante la connessione a una condivisione di rete


191

Quando ci si connette a una condivisione di rete per la quale l'utente corrente (nel mio caso, un utente del servizio abilitato alla rete) non ha diritti, è necessario fornire nome e password.

So come farlo con le funzioni Win32 (il WNet* famiglia di mpr.dll), ma vorrei farlo con la funzionalità .Net (2.0).

Quali opzioni sono disponibili?

Forse qualche informazione in più aiuta:

  • Il caso d'uso è un servizio Windows, non un'applicazione Asp.Net.
  • Il servizio è in esecuzione con un account che non ha diritti sulla condivisione.
  • L'account utente necessario per la condivisione non è noto sul lato client.
  • Il client e il server non sono membri dello stesso dominio.

7
Anche se non ti sto dando una risposta utile, posso fornire un'anti-risposta. La rappresentazione e la generazione di un processo come positato da Marc non funzionerà quando il server e il client non si trovano nello stesso dominio, a meno che non ci sia un trust tra i due domini. Se c'è un trust, allora penso che funzionerà. Avrei appena risposto come commento a quello di Marc, ma non ho abbastanza rappresentante per commentare. : - /
Moose,

Risposte:


152

È possibile modificare l'identità del thread oppure P / Invoke WNetAddConnection2. Preferisco quest'ultima, poiché a volte ho bisogno di mantenere più credenziali per posizioni diverse. Lo avvolgo in un IDisposable e chiamo WNetCancelConnection2 per rimuovere successivamente i crediti (evitando l'errore di nomi utente multipli):

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

4
Il servizio non è membro del dominio di destinazione - la rappresentazione non può funzionare poiché non si sarebbe in grado di creare il token di sicurezza localmente e impersonarlo. PInvoke è l' unico modo.
stephbu,

@MarkBrackett So che questa è una vecchia risposta, ma forse sai ancora ... l'accesso sarà concesso solo al programma o anche all'utente connesso tramite explorer?
Brezza

@Breeze - Non l'ho provato, ma mi aspetto che si autentichi per la sessione di accesso; quindi se il tuo programma è in esecuzione come utente connesso, anche loro avrebbero accesso (almeno per la durata dell'operazione).
Mark Brackett,

8
Le definizioni di readCredentials e writeCredentials potrebbero essere incluse nella risposta.
Anders Lindén,

2
Se ricevi l' errore 53 , assicurati che il percorso non finisca con un "\"
Mustafa S.

327

Mi è piaciuta così tanto la risposta di Mark Brackett che ho fatto la mia rapida implementazione. Ecco se qualcun altro ne ha bisogno in fretta:

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
Dovrebbe davvero essere throw new Win32Exception(result);, poiché WNetAddConnection2 restituisce i codici di errore win32 ( ERROR_XXX)
torvin,

2
Questo è un piccolo brillante pezzo di codice. Necessario accedere a un sistema UNIX per ottenere un elenco di directory per la stampa su un'applicazione Web MVC5 e questo ha funzionato. 1 !!!
Tay,

3
Per compilare il codice sopra riportato sono necessarie le seguenti istruzioni using: using System.Net; utilizzando System.Runtime.InteropServices; utilizzando System.ComponentModel;
Matt Nelson,

4
mi dispiace aggiornare quel vecchio thread, ma sembra che non chiuda la connessione al termine del blocco. Ho un programma per caricare poche foto, la prima va bene, la seconda non riesce. La connessione viene rilasciata quando il programma viene chiuso. Qualche consiglio?
arti

3
Abbiamo avuto lo stesso problema con te, @arti. Impostando semplicemente nome utente e password NetworkCredentialsull'oggetto l'applicazione è stata in grado di connettersi una volta all'unità di rete. Successivamente, abbiamo ricevuto ERROR_LOGON_FAILURE ad ogni tentativo fino al riavvio dell'applicazione. Abbiamo quindi provato a fornire anche il dominio NetworkCredentialsull'oggetto e all'improvviso ha funzionato! Non ho idea del perché ciò abbia risolto il problema, in particolare il fatto che funzionasse per connettersi una volta senza il dominio.
Il

50

Oggi 7 anni dopo sto affrontando lo stesso problema e vorrei condividere la mia versione della soluzione.

È pronto per il copia e incolla :-) Ecco qui:

Passo 1

Nel tuo codice (ogni volta che devi fare qualcosa con le autorizzazioni)

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

Passo 2

Il file Helper che fa una magia

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 Secondo la documentazione su LogonUser , funziona solo per gli utenti sul computer locale: "La funzione LogonUser tenta di accedere a un utente al computer locale. Il computer locale è il computer da cui è stato chiamato LogonUser. Non è possibile utilizzare LogonUser per accedere a un computer remoto. "Riceverai un errore" Win32Exception: il nome utente o la password non sono corretti. " Quindi suppongo che le macchine debbano essere almeno nello stesso dominio.
Charles Chen,

1
@CharlesChen Ho appena dimostrato che funziona bene su tutti i domini, FYI. Il server su cui sto eseguendo questo si trova in una DMZ e si sta sicuramente connettendo a un file server su un dominio diverso, attraverso un firewall. Snippet assassino Pavel, tu sei l'uomo, e questa probabilmente dovrebbe essere la risposta accettata oggi.
Brian MacKay,

Questa è un'ottima soluzione! Grazie, Pavel Kovalev.
STLDev,

funziona su ldap? dice che non ho un server di accesso disponibile.
sto

28

Ho cercato molti metodi e l'ho fatto a modo mio. È necessario aprire una connessione tra due macchine tramite il comando NET USE del prompt dei comandi e dopo aver terminato il lavoro cancellare la connessione con il prompt dei comandi NET USE "myconnection" / eliminare.

È necessario utilizzare il processo Prompt dei comandi dal codice dietro in questo modo:

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

L'uso è semplice:

SaveACopyfileToServer(filePath, savePath);

Ecco le funzioni:

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

E anche la funzione 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;
    } 

Questa funzione ha funzionato molto velocemente e stabile per me.


1
Nel caso in cui la mappatura della condivisione fallisca, quali sarebbero i codici di ritorno?
surega,

14

La soluzione Luke Quinane sembra buona, ma ha funzionato solo parzialmente nella mia applicazione ASP.NET MVC. Avendo due condivisioni sullo stesso server con credenziali diverse ho potuto usare la rappresentazione solo per la prima.

Il problema con WNetAddConnection2 è anche che si comporta in modo diverso su diverse versioni di Windows. Ecco perché ho cercato alternative e ho trovato la funzione LogonUser . Ecco il mio codice che funziona anche in 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;
    }
}

Uso:

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

//do your stuff here

impersonationContext.Leave();

2
questo approccio ha funzionato bene per me, ma nei miei test ho notato che quando si utilizza una password errata con un account utente di dominio, quell'utente viene immediatamente portato nello stato bloccato. la nostra politica di dominio richiede 3 tentativi di accesso non riusciti prima che ciò accada, ma tramite questo approccio un brutto tentativo e sei bloccato. Quindi, usa con cautela ...
Kellyb

5

Per VB.lovers l'equivalente VB.NET del codice di Luke Quinane (grazie 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

Un'opzione che potrebbe funzionare è usare WindowsIdentity.Impersonate(e cambiare il thread principal) per diventare l'utente desiderato, in questo modo . Tornando a p / invoke, però, temo ...

Un'altra opzione sfacciata (e altrettanto lontana dall'ideale) potrebbe essere quella di generare un processo per fare il lavoro ... ProcessStartInfoaccetta un .UserName, .Passworde .Domain.

Infine, forse eseguire il servizio in un account dedicato che ha accesso? (rimosso come hai chiarito che questa non è un'opzione).


non penso che il processo sia una cattiva idea. google ha pubblicato alcuni white paper sui vantaggi del multiprocessing in Chrome.
Dustin Getz,

È possibile cambiare l'entità thread in un utente senza account sul computer locale?
gyrolf,

Ad essere sincero, semplicemente non lo so ... Dovresti provare LogonUser con un dominio diverso per scoprirlo.
Marc Gravell

3

OK ... posso resond ..

Disclaimer: ho appena trascorso più di 18 ore al giorno (di nuovo) .. Sono vecchio e smemorato .. Non posso sillabare .. Ho un breve intervallo di attenzione, quindi è meglio che risponda velocemente .. :-)

Domanda:

È possibile cambiare l'entità thread in un utente senza account sul computer locale?

Risposta:

Sì, puoi modificare un'entità thread anche se le credenziali che stai utilizzando non sono definite localmente o si trovano all'esterno della "foresta".

Ho appena riscontrato questo problema durante il tentativo di connettersi a un server SQL con autenticazione NTLM da un servizio. Questa chiamata utilizza le credenziali associate al processo, il che significa che è necessario un account locale o un account di dominio per l'autenticazione prima di poter impersonare. Blah, blah ...

Ma...

La chiamata a LogonUser (..) con l'attributo ???? _ NEW_CREDENTIALS restituirà un token di sicurezza senza tentare di autenticare le credenziali. Kewl .. Non è necessario definire l'account all'interno della "foresta". Una volta ottenuto il token, potrebbe essere necessario chiamare DuplicateToken () con l'opzione per abilitare la rappresentazione con conseguente nuovo token. Ora chiama SetThreadToken (NULL, token); (Potrebbe essere & token?) .. Una chiamata a ImpersonateLoggedonUser (token); potrebbe essere richiesto, ma io non la penso così. Cerca

Fai quello che devi fare ..

Chiama RevertToSelf () se hai chiamato ImpersonateLoggedonUser () quindi SetThreadToken (NULL, NULL); (Penso ... cercalo), quindi CloseHandle () sulle maniglie create ..

Nessuna promessa, ma questo ha funzionato per me ... Questo è in cima alla mia testa (come i miei capelli) e non posso scrivere !!!



1

Portato anche su F # da usare con 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

Dovresti cercare di aggiungere un simile come questo:

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

Nel tuo web.config.

Maggiori informazioni.


Alcuni sistemi di sicurezza aziendale impediscono l'uso di spacciatori perché non sono in grado di tracciare l'applicazione che la utilizza e devono trovarsi nello stesso dominio o attendibile. Penso che sia stato individuato un supporto impersonale. Un account di servizio di dominio con pinvoke sembra essere la strada da percorrere.
Jim,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.