WindowsIdentity.RunImpersonated下无法访问System.Drawing.Common程序集
Windows身份模拟场景下加载System.Drawing.Common程序集访问拒绝的排查与解决
触发场景
通过WindowsIdentity.RunImpersonated执行身份模拟,读取网络共享路径下的图片资源时,在模拟身份的执行上下文内触发程序集加载失败,抛出访问拒绝类异常。当前业务的核心执行代码如下:
WindowsIdentity.RunImpersonated(safeAccessTokenHandle,() => { string[] files = Directory.GetFiles(path, pattern); if (files.Length > 0) { foreach (string file in files) { string[] f = file.Split('.'); FileStream fstream = new FileStream(file, FileMode.Open); Bitmap bitmap = new Bitmap(fstream); MemoryStream ms = new MemoryStream(); bitmap.Save(ms, ImageFormat.Jpeg); byte[] byteImage = ms.ToArray(); model.Archive.Add(Convert.ToBase64String(byteImage)); fstream.Close(); } } });
实际运行时捕获到的异常信息为:
FileLoadException: Could not load file or assembly 'System.Drawing.Common, Version=5.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51'. Access is denied.
故障原因
关于被模拟用户对程序集没有访问权限的判断,本质上是Windows身份模拟的两个默认特性叠加导致的:
- CLR的程序集加载是按需触发的:如果主进程在进入模拟上下文之前,从未引用过
System.Drawing.Common中的具体类型,CLR不会提前完成该程序集的加载,直到代码首次调用Bitmap、ImageFormat等类型时,才会触发程序集文件的磁盘读取流程。 - 被模拟的身份权限范围是受限的:该身份仅能访问提前配置了共享/本地访问权限的目标资源,而应用程序目录下的
System.Drawing.Common.dll文件,默认仅对启动进程的原始身份(如IIS应用池账号、Windows服务运行账号)开放读取权限,被模拟的普通域用户没有权限读取该DLL文件,最终触发当前的访问拒绝异常。
可落地的解决方案
- 将程序集加载逻辑移到模拟上下文之外:在调用
RunImpersonated之前,主动触发一次System.Drawing.Common的程序集加载,让程序集用进程的原始运行身份完成加载、映射到内存中,后续模拟上下文中调用该程序集的类型时,CLR不会再重复读取磁盘上的DLL文件。示例代码如下:
// 进入模拟上下文前,提前触发System.Drawing.Common加载 using var preloadBitmap = new Bitmap(1, 1); // 再执行业务模拟逻辑 WindowsIdentity.RunImpersonated(safeAccessTokenHandle, () => { // 原有图片处理逻辑保持不变 });
- 补充目录访问权限配置:给应用程序的部署目录开放读取权限,覆盖所有需要参与身份模拟的域账号,让被模拟的身份能够正常读取应用目录下的程序集文件。这种方式不需要修改业务代码,但运维配置成本较高,不推荐作为长期方案。
- 替换图片处理组件:如果业务仅需要完成图片格式转换、不需要调用GDI+的绘图能力,可以将
System.Drawing.Common替换为纯托管实现的图片处理库,从根源上减少对系统组件、本地文件权限的依赖。
代码优化提醒
- 原有代码中的
FileStream、Bitmap、MemoryStream资源没有做异常兜底释放,一旦执行过程中出现报错,很容易出现文件句柄泄漏,锁死共享文件夹中的图片文件。建议统一通过using声明管理非托管资源,保证异常场景下资源也能被正常释放。 .NET 6及以上版本中,System.Drawing.Common默认仅支持Windows平台,若部署环境包含非Windows系统,哪怕解决了权限问题也会触发平台兼容类异常。
内容的提问来源于stack exchange,提问作者Raif
相关产品推荐
相关产品推荐

