当前位置: 首页 > 编程笔记 >

c# 使用特定帐号密码访问Windows网路共享

翟弘
2023-03-14
本文向大家介绍c# 使用特定帐号密码访问Windows网路共享,包括了c# 使用特定帐号密码访问Windows网路共享的使用技巧和注意事项,需要的朋友参考一下

透过程式存取Windows网路分享的档案也算常见需求,但存取身分是个问题。之前我惯用的技巧是用有权限的AD网域帐号执行排程存取网路分享,但这招要搬进网站或遇到不同网路分享用不同帐号便会破功。最近遇上类似议题,直觉要得回头靠WinAPI Impersonation解决,之前曾写过通用元件,担心11年前Windows Vista/7时代的作品有点过时,就爬文找找更好的做法。

之前的变身做法是改变Thread的执行身分,然而针对网路分享还有另一个WinAPI - WNetAddConnection2,可做到对多个网路分享使用不同登入身分。在stackoverflow找到有人分享把它包成搭配using使用的Context物件,符合我惯用的风格,二话不说,按赞并写文分享。

为方便使用,我再做了一层包装,写了一个NetworkCopier,将查目录或复制档案动作简化成Copy(srcNetPath, targetPath, domain, userId, passwd)、DirFiles(srcNetPath, domain, userId, passwd),并支援预设帐密可省略输入domain, userId, passwd;另外还有GetConnetionContext(path, domain, userId, passwd) 可取回NetworkConnection 物件方便用同一连线身分进行多项操作,若来源与目的属不同网路分享则可套叠多重身分,写成:

using (var ctxA = NetworkCopier.GetConnetionContext("\\SvrA\Share", MyAD", "userX", "***")
{
 using (var ctxB = NetworkCopier.GetConnetionContext("\\SvrB\Share", MyAD", "userY", "***") 
 {
  File.Copy(@"\\SvrA\Share\SubFolder\test.txt", @"\\SvrB\Share\test.txt");
  File.Copy(@"\\SvrA\Share\hello.txt", @"\\SvrB\Share\Temp\hello.txt");
 }
}

建立NetworkConnection时,需要引入共享路径而不是完整路径,例如要访问\\SvrA\Share\SubFolder\test.txt,建立NetworkConnection的参数为\\SvrA\Share\,为省去人工截取的麻烦,我写了一段正则表达式更顺手。

完整程式如下,需要的朋友请自取使用:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Net;
using System.Runtime.InteropServices;
using System.Text.RegularExpressions;
using System.Web;

namespace MyApp.Models
{
 public class NetworkCopier
 {
  static string defaultDomain = null;
  static string defaultUserId = null;
  static string defaultPasswd = null;
  static NetworkCopier()
  {
   try
   {
    //TODO: 由設定檔、Registry 或 DB 取得帳號設定,密碼記得要加密保存
    var p = ReadCredentialInfo().Split('\t');
    defaultDomain = p[0];
    defaultUserId = p[1];
    defaultPasswd = p[2];
   }
   catch { }
  }
  static string NotNull(string s)
  {
   if (string.IsNullOrEmpty(s)) 
    throw new ApplicationException("未設定預設登入身分");
   return s;
  }
  static string DefaultDomain => NotNull(defaultDomain);
  static string DefaultUserId => NotNull(defaultUserId);
  static string DefaultPassword => NotNull(defaultPasswd);
  static string GetSharePath(string path)
  {
   var m = Regex.Match(path, @"^\\\\[^\\]+\\[^\\]+");
   if (m.Success) return m.Value;
   return path;
  }
  public static void Copy(string srcPath, string dstPath, string domain = null, string userId = null, string passwd = null)
  {
   using (new NetworkConnection(GetSharePath(srcPath), 
    new NetworkCredential(userId ?? DefaultUserId, passwd ?? DefaultPassword, domain ?? DefaultDomain)))
   {
    File.Copy(srcPath, dstPath);
   }
  }
  public static string[] DirFiles(string path, string pattern, string domain = null, string userId = null, string passwd = null)
  {
   using (new NetworkConnection(GetSharePath(path), 
    new NetworkCredential(userId ?? DefaultUserId, passwd ?? DefaultPassword, domain ?? DefaultDomain)))
   {
    return Directory.GetFiles(path, pattern);
   }
  }
  
  public static GetConnectionContext(string path, string domain = null, string userId = null, string passwd = null) 
  {
   return new NetworkConnection(GetSharePath(path), 
    new NetworkCredential(userId ?? DefaultUserId, passwd ?? DefaultPassword, domain ?? DefaultDomain));
  }
  
 }
 //引用來源: https://stackoverflow.com/a/1197430/288936
 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
 }
}

以上就是c# 使用特定帐号密码访问Windows网路共享的详细内容,更多关于c# 访问Windows网路共享的资料请关注小牛知识库其它相关文章!

 类似资料:
  • 我想授予服务帐户访问Google Secrets Manager中的秘密的权限。 我可以像这样获得这个秘密: 但是当我的服务号尝试相同的命令时,gCloud会发出以下错误: 错误:(gcloud.beta.secrets.versions.access)权限被拒绝:请求的身份验证范围不足。 主要问题是:我还需要做些什么来确保服务帐户可以访问该机密? 我已授予该服务帐户“roles/secretma

  • 我正在尝试通过我的android应用程序访问特定帐户的google drive。此外,我还可以使用google选项登录,这样用户就可以通过google登录应用程序,这将是play services使用的google帐户。 但是,我想在特定的google drive帐户上存储一些文件,比如说

  • 问题内容: 在Windows XP计算机上安装的PHP(XAMPP)中,试图读取本地网络服务器上存在的目录。我用来检查它是否是我可以读取的目录。 在Windows资源管理器中,键入并显示该目录。当我映射网络驱动器时,也可以访问它。 在PHP中,我具有该脚本: 因为我尝试过: 和 但是我没有成功吗?任何的想法?谢谢 问题答案: 我通过更改服务器注册表中的某些内容来解决该问题,如本次讨论的最后一个答案

  • 我在Windows上使用MySQL(我希望我使用的是Mac,但由于某些问题,我正在使用Bootcamp),并且我遇到了一个我认为以前遇到过的问题:标题中写的错误。我想我之前可能已经解决了这个问题,通过控制面板擦除MySQL,并从ProgramFiles中删除隐藏文件夹,ProgramData和MySQL中的所有内容,然后重新安装它。这很麻烦,消耗了很多时间。如果我一次又一次地遇到这样的错误,这绝对

  • 问题 你有一些C函数已经被编译到共享库或DLL中。你希望可以使用纯Python代码调用这些函数, 而不用编写额外的C代码或使用第三方扩展工具。 解决方案 对于需要调用C代码的一些小的问题,通常使用Python标准库中的 ctypes 模块就足够了。 要使用 ctypes ,你首先要确保你要访问的C代码已经被编译到和Python解释器兼容 (同样的架构、字大小、编译器等)的某个共享库中了。 为了进行

  • 我正在尝试从web应用程序连接到azure帐户存储,我得到了以下错误:“类型的异常-'Microsoft。“windows azure . storage . storage exception”在Microsoft.WindowsAzure.Storage.dll中发生,但未在用户代码中处理 其他信息:无法解析远程名称:“xxx.table.core.windows.net” 我在配置中只提供x