74

내 .NET 2.0 응용 프로그램에서는 디렉터리에 파일을 만들고 쓸 수있는 충분한 권한이 있는지 확인해야합니다. 이 목적을 위해 파일을 만들고 단일 바이트를 쓰고 나중에 사용 권한이 있는지 테스트하기 위해 자체를 삭제하려고 시도하는 다음 함수가 있습니다.

나는 최선의 방법을 확인하는 것은 실제로 시도하고 예외를 잡는 것이었다. 나는 예외적 인 캐치 (catch)에 대해 특히 행복하지는 않다. 그렇기 때문에 이보다 더 좋은 방법이 있을까?

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;
        }
    }


  • 코드를 보내 주셔서 감사합니다.하지만 사용자가 글을 쓸 수는 있지만 삭제할 수 없으면 쓰기 권한이 누락되었다는 잘못된 인상을받을 수 있습니다. FileMode.Create를 사용하고 파일 삭제를 제거하기 위해 이것을 바꿀 것입니다. 분명히이 코드는 더 이상 필요하지 않지만 향후 독자를 위해 작성했습니다. - n00b
  • string fullPath = directory + TEMP_FILE;fullPath를 얻기 위해 문자열을 연결하는 대신 Path.Combine 메서드를 사용하십시오.Path.Combine(directory, TEMP_FILE) - nomail
  • 누군가가 펀치를 치고 다음 날 펀치를 당하면 어떨까요? 이틀 후에 펀치를 치고 펀치를하면? 사람들이 그런 일을하지 않을 것이라고 확신하지만 행동을 정의해야합니다. - Scott Hannen

8 답변


22

답변리차드제이슨일종의 올바른 방향입니다. 그러나 당신이해야 할 일은유효 사용 권한 계산하기코드를 실행하는 사용자 ID 위의 예에서는 그룹 구성원 자격을 올바르게 설명하지 않습니다.

나는 꽤 확신한다.키스 브라운이 일을하는 몇 가지 코드가있다.위키 버전(현재 오프라인 상태 임).NET 개발자를위한 Windows 보안 가이드. 이것은 또한 그의프로그래밍 Windows 보안책.

효과적인 사용 권한을 계산하는 것은 희소하고 코드가 파일을 만들려고 시도하는 것이 아니며 발생하는 보안 예외를 잡는 것은 아마도 최소한의 저항의 길일 것입니다.


  • 또한 신뢰할 수있는 유일한 방법이기도합니다. 그렇지 않으면 누군가가 확인과 실제로 저장을 시도하는 것 사이에서 허가를 변경할 수 있습니다 (있을 수는 없지만 가능합니다). - Chris Chilvers
  • 고마워. 그래서 내 코드에서해야 할 유일한 변화는 일반적인 '예외'대신 보안 예외를 잡는 것입니다. - Andy
  • @Andy - 유효 권한을 계산하기위한 코드를 작성하지 않으려면 네, 최소한 저항의 길입니다. - Kev
  • 왜 모든 것이 그렇게 복잡해 져야합니까! - Vidar
  • @ 트리 인코 - 내가 인용 한 기사를 읽으시 길 바랍니다.groups.google.com/group/…- 컴퓨팅유효한사용 권한은 소리만큼 간단하지 않습니다. 내 손님이되어 나를 잘못 입증 할 수있는 대답을하십시오. - Kev

46

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"Flags"btw라고 불리는 것을 사용하고 있습니다. 만약 당신이 정말로 무엇을 읽어야하는지 모르겠다면 :)


  • 디렉토리에 실제로 ACL을 가져올 수 없다면 예외가 발생합니다. - blowdart
  • 그것이 무엇을 확인합니까? 해당 디렉토리에는 쓰기 권한이 있지만 어떤 사용자입니까? :) - Ivan G.
  • 현재 사용자에게 쓰기 권한이 있는지 확인하려는 경우에만 작동합니다. - Donny V.
  • @aloneguid : & quot; GetAccessRules & quot; 메서드는 AuthorizationRuleCollection을 반환합니다. AthorizationRule 클래스에는 IdentityReference 속성이 있습니다.이 런타임 유형은 IdAityReference 유형 (NTAccount 또는 Security)에서 파생 된 두 가지 유형 중 하나가되며 GetAccessRules에 대한 호출에서 지정할 수 있습니다. IdentityReference 인스턴스 (또는 파생 된 유형)를 통해 규칙을 적용 할 사용자를 찾을 수 있습니다. SID 또는 NTAccount 이름 형식입니다. - Triynko
  • 비 관리자 응용 프로그램이있는 Windows 7에서 시스템 디스크에서이 도구를 실행하면 true를 반환하지만 c : \에 쓰려고하면 액세스 할 수 없다는 예외가 발생합니다! - Peter

30

Deny우선하다Allow. 로컬 규칙은 상속 된 규칙보다 우선합니다. 나는 여러 가지 해결책을 보았지만 (여기에 몇 가지 답변을 포함), 아무도 규칙이 있는지 여부를 고려하지 않았다.계승 된아닙니다. 따라서 규칙 상속 (클래스에 깔끔하게 래핑 됨)을 고려한 다음 접근 방식을 제안합니다.

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;
    }
}

그러나 필자는 항상 파일 액세스 권한을 쿼리 할 수있는 권한이 없으므로 원격 컴퓨터에서이 기능이 작동하지 않는다는 경험을했습니다. 이 경우 해결책은 시도하는 것입니다. "실제"파일로 작업하기 전에 액세스 권한을 알아야하는 경우 임시 파일을 만들려고해도됩니다.


  • 밖으로 시도하고 그냥 작동합니다! 고맙습니다! 너는 내 하루를 보냈다! - GiveEmTheBoot
  • 이 대답은 그것을 달성하는 가장 좋은 방법이라고 생각합니다. 다른 답변도 결과를 얻는 데 같은 방법을 사용하지만,이 대답 만이 상속 된 규칙과 로컬 규칙을 계산하기 때문에 가장 정확한 것입니다. 감사 & 축하합니다. - Tolga Evcimen

18

이 질문에 대한 Kev의 대답은 실제로 코드를 제공하지 않으며 액세스 권한이없는 다른 리소스를 가리키고 있습니다. 그래서 여기에 함수에 대한 나의 최선의 시도가있다. 그것은 실제로보고있는 권한이 "쓰기"권한이고 현재 사용자가 해당 그룹에 속해 있는지 확인합니다.

그것은 네트워크 경로 또는 기타와 관련하여 완전하지 않을 수도 있지만 쓰기 목적으로 "Program Files"아래에있는 로컬 구성 파일을 확인하는 것만으로도 충분합니다.

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;
    }
}


  • 이 하나의 그룹에 대해 작동하지 않지만 사실상 경우에만 계정 이름을 추가했습니다. - Random
  • 이것과 관련된 것은 & quot; (S-1-5-21-397955417-626881126-188441444-512) & quot;입니다. 형식 형식? 그 문자열을 문제 해결과 같은 SecurityIdentifier로 변환 했습니까? 귀하의 의견에 따라 그것이 현재 당신을 위해 작동하는지 여부는 분명하지 않습니다. - Bryce Wagner
  • & quot; rule.IdentityReference.Value & quot; currentuser.IsInRole ()의 매개 변수로 일반 "domain \ user"규칙에 따라 일치시키려는 IsInRole (string) 메서드를 사용합니다. 값. 그래서 사용자 이름 문자열 대신 SID 문자열을 밀고 있습니다. 그러나 앞에 줄을 사용하면 주어진 SID의 사용자와 일치하는 SecurityIdentifier 개체를 얻을 수 있습니다. 그 "문자열" 인수 오버로드는 devs에 대한 작은 트랩입니다. 다시 한번 SID 문자열 표현이 아닌 재 검증 가능 형식의 계정 또는 그룹 이름을 허용합니다. - Random
  • 문제는 "new SecurityIdentifier (SDDLFormat)" 일반 그룹 이름으로 작업하지 않습니다 (argment 예외가 발생 함). 그래서 SDDL 형식인지 확인해 보았습니다. - Bryce Wagner
  • 이 솔루션은 나를 위해 일했지만 네트워크 폴더에 하나의 문제가있었습니다. 폴더에 대한 쓰기 규칙을 허용하는 액세스 규칙이 있습니다.BUILTIN\Administrators. 그리고 내 지역 방송국 관리자이기 때문에 실수로 반환했습니다.true. - Ilia Barahovski

5

IMO, 평소와 같은 디렉토리로 작업해야하지만, 사용하기 전에 권한을 확인하는 대신 UnauthorizedAccessException을 처리하고 적절하게 대응할 수있는 올바른 방법을 제공하십시오. 이 방법은 오류가 발생하기 쉽고 훨씬 쉽습니다.


  • 아마도이 방법이 더 쉽고 많은 것이라고 말할 수 있습니다.적게오류가 발생하기 쉽습니다. & # 39; - cjbarth

3

방금 만든 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);
            }
        }
    }
}

여기에참조 할 수도 있습니다. 내 코드는 디렉터리에 쓰기를 시도하기 전에 사용 권한을 확인하는 방법에 대한 아이디어를 줄 수 있습니다.



0

이 링크에 따르면 :http://www.authorcode.com/how-to-check-file-permission-to-write-in-c/

기존의 클래스 SecurityManager를 사용하는 것이 더 쉽습니다.

string FileLocation = @"C:\test.txt";
FileIOPermission writePermission = new FileIOPermission(FileIOPermissionAccess.Write, FileLocation);
if (SecurityManager.IsGranted(writePermission))
{
  // you have permission
}
else
{
 // permission is required!
}

하지만 이제는 더 이상 사용하지 않는 것 같지만 대신 PermissionSet을 사용하는 것이 좋습니다.

[Obsolete("IsGranted is obsolete and will be removed in a future release of the .NET Framework.  Please use the PermissionSet property of either AppDomain or Assembly instead.")]


-1

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);

        }


  • 무엇입니까WellKnownSidType.WorldSid? - Kiquenet

연결된 질문


관련된 질문

최근 질문