it-swarm-vi.tech

Kiểm tra quyền ghi thư mục và tập tin trong .NET

Trong ứng dụng .NET 2.0 của tôi, tôi cần kiểm tra xem có đủ quyền để tạo và ghi vào tệp vào một thư mục hay không. Cuối cùng, tôi có chức năng sau đây cố gắng tạo một tệp và viết một byte cho nó, sau đó xóa chính nó để kiểm tra xem có tồn tại quyền hay không.

Tôi đã tìm ra cách tốt nhất để kiểm tra là thực sự thử và làm nó, nắm bắt bất kỳ trường hợp ngoại lệ nào xảy ra. Mặc dù vậy, tôi không đặc biệt hài lòng về việc bắt Ngoại lệ chung, vậy có cách nào tốt hơn hoặc có lẽ là cách được chấp nhận hơn không?

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

Các câu trả lời của RichardJason là sắp xếp đúng hướng. Tuy nhiên, những gì bạn nên làm là tính toán các quyền hiệu quả cho danh tính người dùng đang chạy mã của bạn. Chẳng có ví dụ nào ở trên tài khoản chính xác cho thành viên nhóm chẳng hạn.

Tôi khá chắc chắn Keith Brown đã có một số mã để thực hiện điều này trong phiên bản wiki của mình (ngoại tuyến tại thời điểm này) của Hướng dẫn dành cho nhà phát triển .NET về Windows Security . Điều này cũng được thảo luận chi tiết hợp lý trong Lập trình Windows Security cuốn sách của anh ấy.

Việc tính toán các quyền hiệu quả không dành cho những người yếu tim và mã của bạn để cố gắng tạo một tệp và bắt ngoại lệ bảo mật bị ném có lẽ là con đường ít kháng cự nhất. 

21
Kev

Directory.GetAcessControl(path) làm những gì bạn đang yêu cầu.

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 đang sử dụng thứ gọi là "Cờ" btw mà nếu bạn không biết đó là gì thì bạn thực sự nên đọc tiếp :)

46
richardwiden

Deny được ưu tiên hơn Allow. Quy tắc địa phương được ưu tiên hơn các quy tắc kế thừa. Tôi đã thấy nhiều giải pháp (bao gồm một số câu trả lời được hiển thị ở đây), nhưng không có giải pháp nào trong số chúng tính đến việc liệu các quy tắc có được kế thừa hay không. Do đó, tôi đề xuất cách tiếp cận sau đây xem xét kế thừa quy tắc (được gói gọn gàng vào một lớp):

public class CurrentUserSecurity
{
    WindowsIdentity _currentUser;
    WindowsPrincipal _currentPrincipal;

    public CurrentUserSecurity()
    {
        _currentUser = WindowsIdentity.GetCurrent();
        _currentPrincipal = new WindowsPrincipal(_currentUser);
    }

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

Tuy nhiên, tôi đã có kinh nghiệm rằng điều này không phải lúc nào cũng hoạt động trên các máy tính từ xa vì bạn sẽ không luôn có quyền truy vấn quyền truy cập tệp ở đó. Giải pháp trong trường hợp đó là thử; thậm chí có thể chỉ bằng cách cố gắng tạo một tệp tạm thời, nếu bạn cần biết quyền truy cập ngay trước khi làm việc với các tệp "thực".

31

Câu trả lời được chấp nhận của Kev cho câu hỏi này không thực sự đưa ra bất kỳ mã nào, nó chỉ trỏ đến các tài nguyên khác mà tôi không có quyền truy cập. Vì vậy, đây là nỗ lực tốt nhất của tôi tại chức năng. Nó thực sự kiểm tra xem quyền mà nó đang xem có phải là quyền "Viết" không và người dùng hiện tại có thuộc nhóm thích hợp không.

Nó có thể không hoàn chỉnh đối với các đường dẫn mạng hoặc bất cứ điều gì, nhưng nó đủ tốt cho mục đích của tôi, kiểm tra các tệp cấu hình cục bộ trong "Tệp chương trình" để biết khả năng ghi:

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;
    }
}
18
Bryce Wagner

IMO, bạn cần làm việc với các thư mục như bình thường, nhưng thay vì kiểm tra quyền trước khi sử dụng, hãy cung cấp cách chính xác để xử lý Un tráiAccessException và phản ứng tương ứng. Phương pháp này dễ dàng hơn và ít bị lỗi hơn.

5
arbiter

Hãy thử làm việc với đoạn mã C # này tôi vừa tạo:

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

đây một tài liệu tham khảo bạn cũng có thể xem. Mã của tôi có thể cho bạn ý tưởng về cách bạn có thể kiểm tra quyền trước khi cố gắng ghi vào thư mục.

3
Jason Evans

theo liên kết này: http://www.mastercode.com/how-to-check-file- allow-to-write-in-c/

sử dụng lớp SecurityManager hiện tại dễ dàng hơn

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

nhưng có vẻ như nó đã bị lỗi thời, thay vào đó, nên sử dụng 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.")]
0
Mulder2008