在.NET中检查目录和文件写入权限
在我的.NET 2.0应用程序中,我需要检查是否有足够的权限来创build文件并将其写入目录。 为此,我有下面的函数试图创build一个文件并写入一个字节,之后删除自己来testing权限是否存在。
我认为最好的检查方法是实际尝试并做到这一点,捕捉发生的任何exception。 虽然我不是特别满意一般的exceptioncatch,那么有没有更好的或者更可接受的方式来做这件事?
private const string TEMP_FILE = "\\tempFile.tmp"; /// <summary> /// Checks the ability to create and write to a file in the supplied directory. /// </summary> /// <param name="directory">String representing the directory path to check.</param> /// <returns>True if successful; otherwise false.</returns> private static bool CheckDirectoryAccess(string directory) { bool success = false; string fullPath = directory + TEMP_FILE; if (Directory.Exists(directory)) { try { using (FileStream fs = new FileStream(fullPath, FileMode.CreateNew, FileAccess.Write)) { fs.WriteByte(0xff); } if (File.Exists(fullPath)) { File.Delete(fullPath); success = true; } } catch (Exception) { success = false; } }
理查德和杰森的回答是正确的。 然而,你应该做的是计算运行你的代码的用户身份的有效权限 。 上面的例子都没有正确说明组成员资格。
我很确定Keith Brown有一些代码可以在.NET版本的Windows开发者指南的 wiki版本 (这个时候是离线的)下做这个工作。 这也在他编程Windows安全手册中进行了合理的详细讨论。
计算有效的权限并不适合那些胆小的人,你的代码尝试创build一个文件并捕获抛出的安全exception可能是阻力最小的path。
Directory.GetAcessControl(path)
做你所要求的。
public static bool HasWritePermissionOnDir(string path) { var writeAllow = false; var writeDeny = false; var accessControlList = Directory.GetAccessControl(path); if (accessControlList == null) return false; var accessRules = accessControlList.GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier)); if (accessRules ==null) return false; foreach (FileSystemAccessRule rule in accessRules) { if ((FileSystemRights.Write & rule.FileSystemRights) != FileSystemRights.Write) continue; if (rule.AccessControlType == AccessControlType.Allow) writeAllow = true; else if (rule.AccessControlType == AccessControlType.Deny) writeDeny = true; } return writeAllow && !writeDeny; }
(FileSystemRights.Write & rights) == FileSystemRights.Write
是使用所谓的“标志”顺便说一句,如果你不知道这是什么,你应该真正阅读:)
Deny
优先于Allow
。 本地规则优先于inheritance的规则。 我见过很多解决scheme(包括这里显示的一些答案),但是没有一个考虑规则是否被inheritance 。 因此,我build议以下考虑规则inheritance的方法(整齐地包装成一个类):
public class CurrentUserSecurity { WindowsIdentity _currentUser; WindowsPrincipal _currentPrincipal; public CurrentUserSecurity() { _currentUser = WindowsIdentity.GetCurrent(); _currentPrincipal = new WindowsPrincipal(WindowsIdentity.GetCurrent()); } public bool HasAccess(DirectoryInfo directory, FileSystemRights right) { // Get the collection of authorization rules that apply to the directory. AuthorizationRuleCollection acl = directory.GetAccessControl() .GetAccessRules(true, true, typeof(SecurityIdentifier)); return HasFileOrDirectoryAccess(right, acl); } public bool HasAccess(FileInfo file, FileSystemRights right) { // Get the collection of authorization rules that apply to the file. AuthorizationRuleCollection acl = file.GetAccessControl() .GetAccessRules(true, true, typeof(SecurityIdentifier)); return HasFileOrDirectoryAccess(right, acl); } private bool HasFileOrDirectoryAccess(FileSystemRights right, AuthorizationRuleCollection acl) { bool allow = false; bool inheritedAllow = false; bool inheritedDeny = false; for (int i = 0; i < acl.Count; i++) { var currentRule = (FileSystemAccessRule)acl[i]; // If the current rule applies to the current user. if (_currentUser.User.Equals(currentRule.IdentityReference) || _currentPrincipal.IsInRole( (SecurityIdentifier)currentRule.IdentityReference)) { if (currentRule.AccessControlType.Equals(AccessControlType.Deny)) { if ((currentRule.FileSystemRights & right) == right) { if (currentRule.IsInherited) { inheritedDeny = true; } else { // Non inherited "deny" takes overall precedence. return false; } } } else if (currentRule.AccessControlType .Equals(AccessControlType.Allow)) { if ((currentRule.FileSystemRights & right) == right) { if (currentRule.IsInherited) { inheritedAllow = true; } else { allow = true; } } } } } if (allow) { // Non inherited "allow" takes precedence over inherited rules. return true; } return inheritedAllow && !inheritedDeny; } }
但是,我的经验是,这并不总是在远程计算机上工作,因为您并不总是有权查询那里的文件访问权限。 在这种情况下的解决办法是尝试; 可能甚至只是试图创build一个临时文件,如果你需要知道访问权限之前处理“真实”的文件。
Kev对这个问题所接受的答案实际上并没有给出任何代码,它只是指向其他我无法访问的资源。 所以这是我最好的尝试。 它实际上检查它正在查看的权限是“写入”权限,并且当前用户属于相应的组。
它可能不完整的networkingpath或任何东西,但是这足够我的目的,检查“程序文件”下的本地configuration文件的可写性:
using System.Security.Principal; using System.Security.AccessControl; private static bool HasWritePermission(string FilePath) { try { FileSystemSecurity security; if (File.Exists(FilePath)) { security = File.GetAccessControl(FilePath); } else { security = Directory.GetAccessControl(Path.GetDirectoryName(FilePath)); } var rules = security.GetAccessRules(true, true, typeof(NTAccount)); var currentuser = new WindowsPrincipal(WindowsIdentity.GetCurrent()); bool result = false; foreach (FileSystemAccessRule rule in rules) { if (0 == (rule.FileSystemRights & (FileSystemRights.WriteData | FileSystemRights.Write))) { continue; } if (rule.IdentityReference.Value.StartsWith("S-1-")) { var sid = new SecurityIdentifier(rule.IdentityReference.Value); if (!currentuser.IsInRole(sid)) { continue; } } else { if (!currentuser.IsInRole(rule.IdentityReference.Value)) { continue; } } if (rule.AccessControlType == AccessControlType.Deny) return false; if (rule.AccessControlType == AccessControlType.Allow) result = true; } return result; } catch { return false; } }
国际海事组织,你需要像平常一样使用这样的目录,而不是在使用前检查权限,提供正确的方式来处理UnauthorizedAccessException并作出相应的反应。 这种方法更容易,更不容易出错。
尝试使用我刚刚制作的这个C#代码片段:
using System; using System.IO; using System.Security.AccessControl; using System.Security.Principal; namespace ConsoleApplication1 { class Program { static void Main(string[] args) { string directory = @"C:\downloads"; DirectoryInfo di = new DirectoryInfo(directory); DirectorySecurity ds = di.GetAccessControl(); foreach (AccessRule rule in ds.GetAccessRules(true, true, typeof(NTAccount))) { Console.WriteLine("Identity = {0}; Access = {1}", rule.IdentityReference.Value, rule.AccessControlType); } } } }
这里有一个参考,你也可以看看。 我的代码可能会给你一个想法,试图写入目录之前,如何检查权限。
在我的情况(检查只读共享networking文件夹)只工作http://www.codeproject.com/Articles/14402/Testing-File-Access-Rights-in-NET
private static void GrantAccess(string file) { bool exists = System.IO.Directory.Exists(file); if (!exists) { DirectoryInfo di = System.IO.Directory.CreateDirectory(file); Console.WriteLine("The Folder is created Sucessfully"); } else { Console.WriteLine("The Folder already exists"); } DirectoryInfo dInfo = new DirectoryInfo(file); DirectorySecurity dSecurity = dInfo.GetAccessControl(); dSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.NoPropagateInherit, AccessControlType.Allow)); dInfo.SetAccessControl(dSecurity); }