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

我知道如何用Win32函数(来自mpr.dll的WNet*家族)做到这一点,但想用. net(2.0)功能。

有哪些选择?

也许更多的信息会有所帮助:

用例是一个windows服务,而不是一个Asp。网络应用程序。 该服务运行在一个没有共享权限的帐户下。 客户端不知道共享所需的用户帐户。 客户端和服务器不是同一域的成员。


当前回答

我非常喜欢马克·布兰克特的回答,所以我自己做了一个快速的执行。如果还有人急着要的话,这是:

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;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string LocalName;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string RemoteName;
    [MarshalAs(UnmanagedType.LPWStr)]
    public string Comment;
    [MarshalAs(UnmanagedType.LPWStr)]
    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
}

其他回答

好吧……我可以回应…

免责声明:我刚刚(又)一天工作了18个多小时。我老了,健忘了。我不会拼写。我的注意力持续时间很短,所以我最好快速反应。: -)

问题:

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

答:

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

我刚刚在尝试从服务使用NTLM身份验证连接到SQL服务器时遇到了这个问题。此调用使用与流程关联的凭据,这意味着在进行模拟之前需要通过本地帐户或域帐户进行身份验证。之类的……

但是…

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

做你该做的。

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

没有保证,但这对我很有效……这是在我的头顶(就像我的头发),我不会拼写!!

你应该像这样添加一行:

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

在你的web.config中。

更多的信息。

这肯定是最愚蠢的方法,但它最近对我很有用,而且它简单得可笑。 当然,只能在Windows上使用。

Process.Start("CMDKEY", @"/add:""NetworkName"" /user:""Username"" /pass:""Password""");

然后,在尝试访问共享之前,可能需要使用WaitForExit()。

您可以在最后删除凭证,再次使用CMDKEY命令。

也移植到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

VB。热爱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