C # 사용자에게 폴더에 대한 쓰기 권한이 있는지 테스트


187

실제로 시도하기 전에 사용자가 폴더에 쓸 수 있는지 테스트해야합니다.

Directory.GetAccessControl () 메서드를 사용하여 폴더에 대한 보안 권한을 검색하려고 시도하는 다음 메서드 (C # 2.0)를 구현했습니다 .

private bool hasWriteAccessToFolder(string folderPath)
{
    try
    {
        // Attempt to get a list of security permissions from the folder. 
        // This will raise an exception if the path is read only or do not have access to view the permissions. 
        System.Security.AccessControl.DirectorySecurity ds = Directory.GetAccessControl(folderPath);
        return true;
    }
    catch (UnauthorizedAccessException)
    {
        return false;
    }
}

내가 쓰기 액세스를 테스트하는 방법을 인터넷 검색 할 때 이와 같은 것은 나타나지 않았으며 실제로 Windows에서 권한을 테스트하는 것은 매우 복잡해 보였습니다. 나는 지나치게 단순화하고 있으며이 방법이 효과가있는 것처럼 보이지만이 방법이 강력하지 않다는 것에 우려하고 있습니다.

현재 사용자에게 쓰기 액세스 권한이 있는지 테스트하는 방법이 올바르게 작동합니까?


13
권한을 볼 수 있는 액세스 권한이없는 경우 해당 권한을 쓸 수없는 것과 동일합니까?
deed02392

답변:


61

이것이 C #에서 폴더 액세스를 확인하는 데 유효한 방법입니다. 예외 가 발생할 수있는 유일한 장소는 예외의 오버 헤드가 문제 있는 단단한 루프에서 이것을 호출 해야하는 경우 입니다.

이전 에 다른 비슷한 질문 이있었습니다 .


1
재미있게도 나는 다른 탭에서 다른 질문 중 하나를 열었지만 DirectorySecurity에 대한 답변을 보지 못했습니다. 받아 들인 질문뿐만 아니라 모든 답변 을 읽도록 가르쳐주십시오 .-)
Chris B

Windows에서 긴 경로를 사용할 때도 떨어지지 않습니까?
Alexandru

11
쓰기 권한이 있는지 알려주지 않고 해당 폴더에 대한 권한을 찾을 수 있는지 여부 만 알려줍니다. 또한 쓸 수는 있지만 권한을 찾지 못할 수도 있습니다.
RandomEngy

65

이 게시물의 날짜가 약간 늦었지만 감사합니다.이 코드가 유용 할 수 있습니다.

string path = @"c:\temp";
string NtAccountName = @"MyDomain\MyUserOrGroup";

DirectoryInfo di = new DirectoryInfo(path);
DirectorySecurity acl = di.GetAccessControl(AccessControlSections.All);
AuthorizationRuleCollection rules = acl.GetAccessRules(true, true, typeof(NTAccount));

//Go through the rules returned from the DirectorySecurity
foreach (AuthorizationRule rule in rules)
{
    //If we find one that matches the identity we are looking for
    if (rule.IdentityReference.Value.Equals(NtAccountName,StringComparison.CurrentCultureIgnoreCase))
    {
        var filesystemAccessRule = (FileSystemAccessRule)rule;

        //Cast to a FileSystemAccessRule to check for access rights
        if ((filesystemAccessRule.FileSystemRights & FileSystemRights.WriteData)>0 && filesystemAccessRule.AccessControlType != AccessControlType.Deny)
        {
            Console.WriteLine(string.Format("{0} has write access to {1}", NtAccountName, path));
        }
        else
        {
            Console.WriteLine(string.Format("{0} does not have write access to {1}", NtAccountName, path));
        }
    }
}

Console.ReadLine();

콘솔 앱에 드롭하고 필요한 작업인지 확인하십시오.


바로 목표에! 나를 많이 도와줍니다!
smwikipedia

호출에 대한 예외가 발생 GetAccessControl하지만 소프트웨어가 실제로보고있는 디렉토리에 쓸 수 있습니다 ..?
Jon Cage

@ JonCage-어떤 예외가 있습니까? 아이러니하게도 가장 먼저 떠오르는 것은 보안 문제입니다. 앱이 실행중인 계정에 ACL 정보를 얻을 수있는 권한이 있습니까?
던컨 하우

1
FileSystemAccessRule 유형에 대한 점검을 추가해야합니다. 거부 규칙 인 경우 쓰기 가능으로 잘못보고합니다.
tdemay

2
이것을 사용하려고합니다. 다른 문제를 발견했습니다. 권한이 특정 사용자가 아닌 그룹에만 할당되면 쓰기 권한이 없다고 잘못보고됩니다. 예를 들어, "인증 된 사용자"에게 부여 된 쓰기 액세스
tdemay

63
public bool IsDirectoryWritable(string dirPath, bool throwIfFails = false)
{
    try
    {
        using (FileStream fs = File.Create(
            Path.Combine(
                dirPath, 
                Path.GetRandomFileName()
            ), 
            1,
            FileOptions.DeleteOnClose)
        )
        { }
        return true;
    }
    catch
    {
        if (throwIfFails)
            throw;
        else
            return false;
    }
}

7
이 답변은 권한 위반뿐만 아니라 파일을 작성할 때 발생할 수있는 모든 예외를 포착합니다.
매트 엘렌

7
@GY,, string tempFileName = Path.GetRandomFileName();분명히
Alexey Khoroshikh

3
@Matt, 이것은 실패 이유와 상관없이 "디렉토리가 쓰기 가능합니까?"라는 질문에 정확하게 대답합니다. 오히려 " 내가 디렉토리에 쓸 수 없는지 "에 대답 하십시오. :)
Alexey Khoroshikh

1
이 코드로 오 탐지를 얻습니다. File.Create ()는 실행중인 사용자가 해당 폴더에 쓸 수있는 권한이 없더라도 OK를 실행합니다 (마지막 옵션을 변경하면 임시 파일을 남깁니다). 정말 이상합니다-왜 그런지 알아 내려고 한 시간을 보냈지 만 나는 엉망입니다.
NickG

4
아래에서 시도한 모든 대안 (및 참조 링크)에서 이것은 안정적으로 작동하는 유일한 방법입니다.
TarmoPikaro

24

나는 이것들의 대부분을 시도했지만 그것들은 같은 이유로 거짓 긍정을 준다. 사용 가능한 권한에 대해 디렉토리를 테스트하는 것만으로는 충분하지 않다. 허가. 이를 위해 사용자 ID를 확보하고 FileSystemAccessRule IdentityReference를 포함하는 그룹의 구성원인지 확인하십시오. 나는 이것을 테스트하고 완벽하게 작동합니다 ..

    /// <summary>
    /// Test a directory for create file access permissions
    /// </summary>
    /// <param name="DirectoryPath">Full path to directory </param>
    /// <param name="AccessRight">File System right tested</param>
    /// <returns>State [bool]</returns>
    public static bool DirectoryHasPermission(string DirectoryPath, FileSystemRights AccessRight)
    {
        if (string.IsNullOrEmpty(DirectoryPath)) return false;

        try
        {
            AuthorizationRuleCollection rules = Directory.GetAccessControl(DirectoryPath).GetAccessRules(true, true, typeof(System.Security.Principal.SecurityIdentifier));
            WindowsIdentity identity = WindowsIdentity.GetCurrent();

            foreach (FileSystemAccessRule rule in rules)
            {
                if (identity.Groups.Contains(rule.IdentityReference))
                {
                    if ((AccessRight & rule.FileSystemRights) == AccessRight)
                    {
                        if (rule.AccessControlType == AccessControlType.Allow)
                            return true;
                    }
                }
            }
        }
        catch { }
        return false;
    }

John에게 감사합니다. 코드를 사용하여 사용자 그룹을 식별 참조 규칙으로 다시 확인하기 전까지는 오 탐지가 발생했습니다.
Paul L

1
서비스에 대한 전용 로컬 계정과 같이 액세스 권한은 부여했지만 다른 그룹에는 액세스하지 않은 사용자가 있었기 때문에 identity.Owner == rule.IdentityReference에 대한 추가 검사를 추가해야했습니다.
grinder22

2
AccessControlType 때문에 완전히 철저한 액세스 권한뿐만 아니라 확인해야 거부 규칙, 수, 허용보다 우선 거부 그것이 있어야 종류의 거부를 검사 할 때 (AccessRight & rule.FileSystemRights) > 0하위 액세스 유형이 그의 일부 거부하기 때문에 AccessRight당신이없는 수단 전체를 이용AccessRight
TJ Rockefeller

위에서 언급 한 그라인더 22에서 변경해야했습니다. 액세스 권한이 있지만 액세스 권한이없는 사용자가있는 경우 if (identity.Groups.Contains (rule.IdentityReference)) to if (identity.Groups.Contains (rule.IdentityReference) || 그룹 중 하나에서 t.
ehambright

13

IMHO 디렉토리에 쓸 수 있는지 테스트하는 유일한 100 % 신뢰할 수있는 방법은 실제로 디렉토리에 쓰고 결국 예외를 잡는 것입니다.


13

예를 들어 모든 사용자 (Builtin \ Users)에게이 방법은 잘 작동합니다.

public static bool HasFolderWritePermission(string destDir)
{
   if(string.IsNullOrEmpty(destDir) || !Directory.Exists(destDir)) return false;
   try
   {
      DirectorySecurity security = Directory.GetAccessControl(destDir);
      SecurityIdentifier users = new SecurityIdentifier(WellKnownSidType.BuiltinUsersSid, null);
      foreach(AuthorizationRule rule in security.GetAccessRules(true, true, typeof(SecurityIdentifier)))
      {
          if(rule.IdentityReference == users)
          {
             FileSystemAccessRule rights = ((FileSystemAccessRule)rule);
             if(rights.AccessControlType == AccessControlType.Allow)
             {
                    if(rights.FileSystemRights == (rights.FileSystemRights | FileSystemRights.Modify)) return true;
             }
          }
       }
       return false;
    }
    catch
    {
        return false;
    }
}

8

이 시도:

try
{
    DirectoryInfo di = new DirectoryInfo(path);
    DirectorySecurity acl = di.GetAccessControl();
    AuthorizationRuleCollection rules = acl.GetAccessRules(true, true, typeof(NTAccount));

    WindowsIdentity currentUser = WindowsIdentity.GetCurrent();
    WindowsPrincipal principal = new WindowsPrincipal(currentUser);
    foreach (AuthorizationRule rule in rules)
    {
        FileSystemAccessRule fsAccessRule = rule as FileSystemAccessRule;
        if (fsAccessRule == null)
            continue;

        if ((fsAccessRule.FileSystemRights & FileSystemRights.WriteData) > 0)
        {
            NTAccount ntAccount = rule.IdentityReference as NTAccount;
            if (ntAccount == null)
            {
                continue;
            }

            if (principal.IsInRole(ntAccount.Value))
            {
                Console.WriteLine("Current user is in role of {0}, has write access", ntAccount.Value);
                continue;
            }
            Console.WriteLine("Current user is not in role of {0}, does not have write access", ntAccount.Value);                        
        }
    }
}
catch (UnauthorizedAccessException)
{
    Console.WriteLine("does not have write access");
}

제가 잘못 본게 아니라면,이 매우가 가까운하지만 - 그것은 사실 내려다 fsAccessRule.AccessControlType수를 AccessControlType.Deny.
Jonathan Gilbert

이것은 내 Win7 dev 시스템에서 나를 위해 일했지만 Win10 (테스터 및 내 테스트 시스템 모두)에서 실패합니다. ssds의 수정 (아래 참조)이 수정 된 것으로 보입니다.
winwaed

6

코드는 DirectorySecurity주어진 디렉토리에 대한를 가져오고 보안 정보에 액세스 할 수 없기 때문에 예외를 올바르게 처리합니다. 그러나 샘플에서는 실제로 어떤 액세스가 허용되는지 확인하기 위해 반환 된 객체를 조사하지 않으며 이것을 추가해야한다고 생각합니다.


+1-GetAccessControl을 호출 할 때 예외가 발생하지 않았지만 동일한 디렉토리에 쓰려고 할 때 무단 예외가 발생하는이 문제가 발생했습니다.
Mayo

6

다음은 명시 적 거부 액세스 규칙을 설명하는 CsabaS의 답변 수정 버전입니다 . 이 함수는 디렉토리에 대한 모든 FileSystemAccessRules를 통과하고 현재 사용자가 디렉토리에 액세스 할 수있는 역할을 수행하는지 확인합니다. 이러한 역할을 찾을 수 없거나 사용자가 액세스가 거부 된 역할을하는 경우이 함수는 false를 반환합니다. 읽기 권한을 확인하려면 FileSystemRights.Read를 함수에 전달하십시오. 쓰기 권한을 얻으려면 FileSystemRights.Write를 전달하십시오. 현재 사용자가 아닌 임의의 사용자 권한을 확인하려면 currentUser WindowsIdentity를 원하는 WindowsIdentity로 대체하십시오. 또한 사용자가 디렉토리를 안전하게 사용할 수 있는지 확인하기 위해 이와 같은 기능에 의존하지 않는 것이 좋습니다. 답변은 이유를 완벽하게 설명합니다.

    public static bool UserHasDirectoryAccessRights(string path, FileSystemRights accessRights)
    {
        var isInRoleWithAccess = false;

        try
        {
            var di = new DirectoryInfo(path);
            var acl = di.GetAccessControl();
            var rules = acl.GetAccessRules(true, true, typeof(NTAccount));

            var currentUser = WindowsIdentity.GetCurrent();
            var principal = new WindowsPrincipal(currentUser);
            foreach (AuthorizationRule rule in rules)
            {
                var fsAccessRule = rule as FileSystemAccessRule;
                if (fsAccessRule == null)
                    continue;

                if ((fsAccessRule.FileSystemRights & accessRights) > 0)
                {
                    var ntAccount = rule.IdentityReference as NTAccount;
                    if (ntAccount == null)
                        continue;

                    if (principal.IsInRole(ntAccount.Value))
                    {
                        if (fsAccessRule.AccessControlType == AccessControlType.Deny)
                            return false;
                        isInRoleWithAccess = true;
                    }
                }
            }
        }
        catch (UnauthorizedAccessException)
        {
            return false;
        }
        return isInRoleWithAccess;
    }

Csaba의 코드는 Windows 10에서 나에게 실패했습니다 (그러나 Win7 dev 컴퓨터에서는 괜찮습니다). 위의 문제를 해결하기 위해 나타납니다.
winwaed

4

위의 솔루션은 좋지만 나에게는이 코드가 간단하고 실행 가능하다는 것을 알았습니다. 임시 파일을 만드십시오. 파일이 작성되면 평균 사용자는 쓰기 액세스 권한을 갖습니다.

        public static bool HasWritePermission(string tempfilepath)
        {
            try
            {
                System.IO.File.Create(tempfilepath + "temp.txt").Close();
                System.IO.File.Delete(tempfilepath + "temp.txt");
            }
            catch (System.UnauthorizedAccessException ex)
            {

                return false;
            }

            return true;
        }

3
좋은! 한 가지 사실은 해당 사용자에게 Create권한이 있지만 Delete사용자 에게 쓰기 권한 있어도 false를 반환한다는 것 입니다.
Chris B

코딩에 대한 가장 편리한 답변 :) 또한이 요청 만 사용하지만 동시 요청이 많으면 너무 많은 읽기 / 쓰기로 인해 성능이 느려질 수 있으므로 이러한 경우 다른 답변에 제공된 액세스 제어 방법을 사용할 수 있습니다.
vibs2006

1
Path.Combine대신과 같이 사용하십시오 Path.Combine(tempfilepath, "temp.txt").
ΩmegaMan

3

디렉토리에 쓰기 액세스 권한이 있는지 확인하기 위해 다음 코드 블록을 시도 할 수 있습니다. FileSystemAccessRule을 확인합니다.

string directoryPath = "C:\\XYZ"; //folderBrowserDialog.SelectedPath;
bool isWriteAccess = false;
try
{
    AuthorizationRuleCollection collection =
        Directory.GetAccessControl(directoryPath)
            .GetAccessRules(true, true, typeof(System.Security.Principal.NTAccount));
    foreach (FileSystemAccessRule rule in collection)
    {
        if (rule.AccessControlType == AccessControlType.Allow)
        {
            isWriteAccess = true;
            break;
        }
    }
}
catch (UnauthorizedAccessException ex)
{
    isWriteAccess = false;
}
catch (Exception ex)
{
    isWriteAccess = false;
}
if (!isWriteAccess)
{
    //handle notifications 
}

2

코드에 잠재적 인 경쟁 조건이 있습니다. 확인할 때 폴더에 쓸 수있는 권한이 사용자에게 있지만 실제로 사용자가 폴더에 쓸 때이 권한이 철회됩니까? 쓰기는 예외를 처리하여 잡아서 처리해야합니다. 따라서 초기 점검은 의미가 없습니다. 쓰기 만하고 예외를 처리 할 수도 있습니다. 이것은 상황에 맞는 표준 패턴입니다.



1

문제의 파일에 접근하는 것만으로는 충분하지 않습니다. 테스트는 프로그램을 실행하는 사용자의 권한으로 실행됩니다. 반드시 테스트하려는 사용자 권한이 아닙니다.


0

Ash에 동의합니다. 괜찮습니다. 또는 선언적 CAS를 사용하여 실제로 프로그램에 액세스 할 수없는 경우 처음부터 프로그램이 실행되지 못하게 할 수 있습니다.

CAS 기능 중 일부는 내가 들었던 것에서 C # 4.0에 없을 수 있다고 생각합니다. 문제가 있는지 확실하지 않습니다.


0

허용 된 답변에서 권장하는대로 Windows 7에서 GetAccessControl ()이 예외를 throw하지 못했습니다.

나는 sdds의 답변을 변형하여 사용했습니다 .

        try
        {
            bool writeable = false;
            WindowsPrincipal principal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
            DirectorySecurity security = Directory.GetAccessControl(pstrPath);
            AuthorizationRuleCollection authRules = security.GetAccessRules(true, true, typeof(SecurityIdentifier));

            foreach (FileSystemAccessRule accessRule in authRules)
            {

                if (principal.IsInRole(accessRule.IdentityReference as SecurityIdentifier))
                {
                    if ((FileSystemRights.WriteData & accessRule.FileSystemRights) == FileSystemRights.WriteData)
                    {
                        if (accessRule.AccessControlType == AccessControlType.Allow)
                        {
                            writeable = true;
                        }
                        else if (accessRule.AccessControlType == AccessControlType.Deny)
                        {
                            //Deny usually overrides any Allow
                            return false;
                        }

                    } 
                }
            }
            return writeable;
        }
        catch (UnauthorizedAccessException)
        {
            return false;
        }

도움이 되었기를 바랍니다.


0

나는 같은 문제에 직면했다 : 특정 디렉토리에서 읽고 쓸 수 있는지 확인하는 방법. 나는 실제로 그것을 테스트하는 쉬운 해결책으로 끝났다. 여기에 간단하지만 효과적인 해결책이 있습니다.

 class Program
{

    /// <summary>
    /// Tests if can read files and if any are present
    /// </summary>
    /// <param name="dirPath"></param>
    /// <returns></returns>
    private genericResponse check_canRead(string dirPath)
    {
        try
        {
            IEnumerable<string> files = Directory.EnumerateFiles(dirPath);
            if (files.Count().Equals(0))
                return new genericResponse() { status = true, idMsg = genericResponseType.NothingToRead };

            return new genericResponse() { status = true, idMsg = genericResponseType.OK };
        }
        catch (DirectoryNotFoundException ex)
        {

            return new genericResponse() { status = false, idMsg = genericResponseType.ItemNotFound };

        }
        catch (UnauthorizedAccessException ex)
        {

            return new genericResponse() { status = false, idMsg = genericResponseType.CannotRead };

        }

    }

    /// <summary>
    /// Tests if can wirte both files or Directory
    /// </summary>
    /// <param name="dirPath"></param>
    /// <returns></returns>
    private genericResponse check_canWrite(string dirPath)
    {

        try
        {
            string testDir = "__TESTDIR__";
            Directory.CreateDirectory(string.Join("/", dirPath, testDir));

            Directory.Delete(string.Join("/", dirPath, testDir));


            string testFile = "__TESTFILE__.txt";
            try
            {
                TextWriter tw = new StreamWriter(string.Join("/", dirPath, testFile), false);
                tw.WriteLine(testFile);
                tw.Close();
                File.Delete(string.Join("/", dirPath, testFile));

                return new genericResponse() { status = true, idMsg = genericResponseType.OK };
            }
            catch (UnauthorizedAccessException ex)
            {

                return new genericResponse() { status = false, idMsg = genericResponseType.CannotWriteFile };

            }


        }
        catch (UnauthorizedAccessException ex)
        {

            return new genericResponse() { status = false, idMsg = genericResponseType.CannotWriteDir };

        }
    }


}

public class genericResponse
{

    public bool status { get; set; }
    public genericResponseType idMsg { get; set; }
    public string msg { get; set; }

}

public enum genericResponseType
{

    NothingToRead = 1,
    OK = 0,
    CannotRead = -1,
    CannotWriteDir = -2,
    CannotWriteFile = -3,
    ItemNotFound = -4

}

그것이 도움이되기를 바랍니다!


0

여기에있는 대부분의 답변은 쓰기 액세스를 확인하지 않습니다. 사용자 / 그룹이 '권한 읽기'(파일 / 디렉토리의 ACE 목록 읽기)가 가능한지 확인합니다.

또한 ACE를 통해 반복하고 보안 식별자와 일치하는지 확인하면 사용자가 권한을 얻거나 잃을 수있는 그룹의 구성원이 될 수 있으므로 작동하지 않습니다. 그보다 더 나쁜 것은 중첩 된 그룹입니다.

나는 이것이 오래된 실이라는 것을 알고 있지만 지금 보는 사람에게는 더 좋은 방법이 있습니다.

사용자에게 읽기 권한이 있으면 Authz API를 사용하여 유효 액세스를 확인할 수 있습니다.

https://docs.microsoft.com/en-us/windows/win32/secauthz/using-authz-api

https://docs.microsoft.com/en-us/windows/win32/secauthz/checking-access-with-authz-api

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.