Windows下 文件权限的设置【持续更新中..】

434 阅读14分钟

最近公司有些业务用到了 Windows下面的文件权限设置。所以针对权限系统相关的知识做一下总结和分享,因为windows授权管理系统非常的复杂,特别是在权限的传播,影响的是文件夹还是文件层面。

1、继承和传播标志的快速预览

下面是微软的msdn上找的一篇文章,讲述了访问规则的设置问题。

每个访问规则要么是显式的,要么是继承的。其中

  • 显示规则:在对象上执行显示操作,添加到对象上的规则
  • 继承规则:来自于父容器

向容器添加新的显式规则时,您可以指定两组标志:一组用于继承,一组用于传播。

继承标志(InheritanceFlags):

  • 容器继承(CI):指定容器继承的规则将适用于当前对象的子容器
  • 对象继承(OI):对象继承规则将适用于子叶对象
  • :权限只作用于当前对象,不会传递给它的子对象,不再向下作用了。

传播标志(PropagationFlags)

  • 仅继承(IO):仅继承标志的意思是该规则仅适用于子对象,而不适用于对象本身
  • 不传播继承(NP):它会影响子对象,但不会影响孙对象
  • :没有特殊的传播规则,权限会正常继承到所有子对象。也就是不加入任何的拦截,0拦截。

下面来展示继承和传播标志如何影响容器,我们目前针对最顶部的文件夹,进行权限设置。

AAA.gif

我从上至下,从左往右的依次解释这张图


image.png

1、WIndows名称为只有该文件夹 (InheritanceFlags.None, PropagationFlags.None)

图中没有设置任何的传播,也就是 InheritanceFlags.None, PropagationFlags.None,权限仅仅是设置在当前文件夹,并没有往下传播。

  • 如果在此文件夹设置了访问权限。那么,我们只能看到C本身,当我们打开"C"的时候,看不到任何的东西,因为我们的访问权限,并没有传递到下面
  • 如果在此文件夹设置完全访问权限,发现自己也是什么也做不了,无法删除文件夹,无法编辑

image.png

图中设置了继承的标志为 容器继承(CI),但是没有设置传播的标志,所以针对C上面的权限,CC,GC这两个文件夹能够看得到,但是CO,GO这两个文件,就看不到了

2、WIndows名称为: 此文件夹和子文件夹(InheritanceFlags.ContainerInherit, PropagationFlags.None)


image.png

图中设置了继承的标志为 对象继承(OI),没有设置传播的标志,也就是能够一直传播下去。仅仅对文件有权限。

3、WIndows名称为: 此文件夹和文件(InheritanceFlags.ObjectInherit, PropagationFlags.None)

  • 如果设置的是访问权限:则只能看到C下面的CO文件,而无法看到CC下面的GO文件

image.png

图中设置了继承标志:容器继承(CI),对象继承(OI),设置了传播标志:仅继承(IO)。也就是当对C进行设置的时候,下面的文件夹,和子文件都能收到影响。仅继承(IO) 这个标志,指的是子级,不包括自己。

4、WIndows名称为: 仅子文件夹和文件(InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.InheritOnly)

  • 如果在C进行设置访问权限,那么,无法直接看到C这个文件夹,而且也无法查看CO文件。但是可以进去到CC文件夹中,看到GC文件夹和GO文件

image.png

图中设置了继承标志:容器继承(CI) 和传播标志:不传播继承(NP)。 意思是影响到当前文件夹和子级的文件夹,

5、Windows名称为:此文件夹和子文件夹(InheritanceFlags.ContainerInherit,PropagationFlags.NoPropagateInherit)

  • 如果给当前对象设置权限,那么只会影响到C和CC。如果设置了访问权限,那么,只能看到C,以及CC文件夹。打开CC文件夹后,什么都不能看到。

  • 仅仅设置了访问权限后,在C文件夹下,只能看,其他的一切,都做不到

  • 如果设置C为完全控制权限,在C下面创建文件夹是OK的。但是在创建文件的时候,没有任何的反应,其实已经创建成功了,只是看不到文件而已。如果这个时候,再次创建文件,则会提示报错,报错提示为:

image.png


image.png

图中设置了继承标志:对象继承(OI) 和 传播标志:不传播继承(NP)。只能作用于当前文件和子文件。

6、Windows名称为:此文件夹和文件(InheritanceFlags.ObjectInherit,PropagationFlags.NoPropagateInherit)

  • 如果设置的访问权限:那么只能看到CO文件
  • 如果设置的操作权限:则无法创建文件夹

image.png

图中设置了继承标志:容器继承(CI)对象继承(OI) 和 传播标志:不传播继承(NP)

只能作用于当前文件夹和当前文件

7、Windows名称为:此文件夹和文件(InheritanceFlags.ContainerInherit|InheritanceFlags.ObjectInherit,PropagationFlags.NoPropagateInherit)

  • 当前设置了完全控制权限,无法修改C的名称,但是可以删除C,只是删除C的时候,C文件夹和CC文件夹不会受到影响,CO这些子文件则会被删除。
  • 可以新增CC子文件夹,但是如果CC文件夹里面,有GC和CO,则不能删除
  • 可以重命名CC文件夹

image.png

8、Windows对应的名称为: 此文件夹和子文件夹和文件

图中设置了继承标志:容器继承(CI)对象继承(OI)

InheritanceFlags : InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit

PropagationFlags : PropagationFlags.None

这种方式的设置,是影响面最广的


image.png

9、Windows对应的名称为: 此文件夹和子文件夹和文件

图中设置了继承标志:容器继承(CI) , 传播标志:仅继承(IO)

InheritanceFlags : InheritanceFlags.ContainerInherit

PropagationFlags : PropagationFlags.InheritOnly

  • 如果设置为访问权限,则C不可见,而能直接打开CC和GC这些子文件夹

  • 如果设置为可编辑:则C不可见,可以在CC文件夹下新增文件夹,GC文件夹下新增文件夹


image.png

10、Windows对应的名称为: 只有文件

图中设置了继承标志:对象继承(OI) , 传播标志:仅继承(IO)

InheritanceFlags : InheritanceFlags.ObjectInherit

PropagationFlags : PropagationFlags.InheritOnly

  • 设置C的完全控制权限,然后再额外加上文件的访问权限。我们就能做到,用户只能针对文件进行写入,而无法做其他的操作

image.png

11、Windows对应的名称为: 只有子文件夹

图中设置了继承标志:容器继承(CI) , 传播标志:仅继承(IO)不传播继承(NP)

InheritanceFlags : InheritanceFlags.ContainerInherit

PropagationFlags : PropagationFlags.InheritOnly | PropagationFlags.NoPropagateInherit

  • 如果设置了访问权限,那么只能打开CC文件夹,且看不到任何的东西
  • 一般的业务场景都是 控制CC文件夹的删除,或者更改权限

image.png

12、Windows对应的名称为: 只有子文件

图中设置了继承标志:对象继承(OI) , 传播标志:仅继承(IO)不传播继承(NP)

InheritanceFlags : InheritanceFlags.ObjectInherit

PropagationFlags : PropagationFlags.InheritOnly | PropagationFlags.NoPropagateInherit

  • 只能控制该文件夹的文件

image.png

13、Windows对应的名称为: 仅子文件夹和文件

图中设置了继承标志:容器继承(CI) ,对象继承(OI) , 传播标志:仅继承(IO)不传播继承(NP)

InheritanceFlags :InheritanceFlags.ContainerInherit, InheritanceFlags.ObjectInherit

PropagationFlags : PropagationFlags.InheritOnly | PropagationFlags.NoPropagateInherit

  • 一般的使用场景是,想针对子级的文件夹或者文件进行操作时,可以附加操作权限,前提是得拥有全部的访问权限,额外增加的。

1、什么是ACL,ACE

2、快速体验权限配置所带来的效果

这个是根据先手动的去设置目录上的权限,然后再通过读取文件夹权限,获取对应关系

public static (InheritanceFlags, PropagationFlags) GetFlags(ApplyForObjectEnum applyForObject)
{
    switch (applyForObject)
    {
       case ApplyForObjectEnum.只有该文件夹:
          return (InheritanceFlags.None, PropagationFlags.None);

       case ApplyForObjectEnum.只有子文件夹:
          return (InheritanceFlags.ContainerInherit, PropagationFlags.InheritOnly);

       case ApplyForObjectEnum.此文件夹和文件:
          return (InheritanceFlags.ObjectInherit, PropagationFlags.None);

       case ApplyForObjectEnum.只有文件:
          return (InheritanceFlags.ObjectInherit, PropagationFlags.InheritOnly);

       case ApplyForObjectEnum.仅子文件夹和文件:
          return (InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit,
             PropagationFlags.InheritOnly);

       case ApplyForObjectEnum.此文件夹和子文件夹和文件:
          return (InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None);

       case ApplyForObjectEnum.此文件夹和子文件夹:
          return (InheritanceFlags.ContainerInherit, PropagationFlags.None);

       default:
          throw new System.NotImplementedException("不存在该枚举类");
    }
}

3、核心解释

(1) InheritanceFlags 的详细解释

Inheritance本身就是继承的意思, InheritanceFlags 就是用来决定权限(比如读、写、执行等)是仅仅作用于当前对象,还是也作用于它的子对象。

1. InheritanceFlags.None

  • 意思:权限只作用于当前对象,不会传递给它的子对象,不再向下作用了。
  • 例子:如果你给一个文件夹设置了权限,只有这个文件夹有这个权限,它里面的文件或子文件夹没有这个权限。

2. InheritanceFlags.ContainerInherit

  • 意思Container是容器的意思,这里是指权限会传递给子文件夹,但不会传递给文件。
  • 例子:如果你给一个文件夹设置了权限,并选择这个选项,那么它的子文件夹会继承这个权限,但文件不会。

3. InheritanceFlags.ObjectInherit

  • 意思Object是对象的意思,这里指权限会传递给文件,但不会传递给子文件夹。
  • 例子:如果你给一个文件夹设置了权限,并选择这个选项,那么这个文件夹里的文件会继承这个权限,但子文件夹不会。

4. InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit

  • 意思:权限能够作用于文件夹和文件

举个例子

假设你有一个叫 Documents 的文件夹,里面有一些子文件夹和文件:现在针对Documents进行权限设置

复制代码
Documents
├── Work (子文件夹)
│   └── Report.docx (文件)
└── Personal (子文件夹)
    └── Photos.jpg (文件)
  • InheritanceFlags.None:如果你设置权限时选择 None,只有 Documents 这个文件夹有这个权限,里面的 WorkPersonal 以及 Report.docxPhotos.jpg 都不会有这个权限。

  • InheritanceFlags.ContainerInherit:如果你选择了 ContainerInherit,那么 Documents 的权限会传递给 WorkPersonal 这些子文件夹,但 Report.docxPhotos.jpg 这些文件不会继承。

  • InheritanceFlags.ObjectInherit:如果你选择了 ObjectInherit,那么 Documents 的权限会传递给 Report.docxPhotos.jpg 这些文件,但 WorkPersonal 这些子文件夹不会继承。

这样,你可以根据需要决定权限是否传递给文件夹、文件,还是都不传递。

(2)PropagationFlags 的详细解释

PropagationFlags 是用来控制权限如何进一步传递的标志,但它只在你设置了 InheritanceFlags 的时候才有作用。简单来说,它决定了权限在子对象之间的传播方式。

1. PropagationFlags.None

  • 意思:没有特殊的传播规则,权限会正常继承到所有子对象。也就是不加入任何的拦截,0拦截。
  • 例子:如果你设置了 InheritanceFlags,并选择 PropagationFlags.None,那么权限会从父文件夹传递给子文件夹,再从子文件夹传递给它的子文件夹,依此类推。

2. PropagationFlags.NoPropagateInherit

  • 意思:不继续传播继承关系。 权限只传递给直接的子对象,但不会再继续传递给更深层次的子对象。
  • 例子:如果你给 Documents 文件夹设置了权限,并选择 NoPropagateInherit,那么 Documents 的权限会传递给它的子文件夹 Work,但 Work 里面的文件 Report.docx 不会再继承这个权限。

3. PropagationFlags.InheritOnly

  • 意思:权限只作为继承使用,不适用于当前对象本身。也就是作用于子对象,但是自己不受影响
  • 例子:如果你给 Documents 设置了 InheritOnly,那么 Documents 文件夹本身不会有这个权限,但它的子文件夹和文件可能会继承到这个权限。

举个例子

假设你有一个叫 RootFolder 的文件夹,里面有子文件夹 SubFolder1SubFolder2,每个子文件夹里又有一些文件:现在针对 RootFolder设置一些权限。

RootFolder
├── SubFolder1
│   └── File1.txt
└── SubFolder2
    └── File2.txt

以下可以设置的规则

  • PropagationFlags.None:权限会从 RootFolder 传递到 SubFolder1SubFolder2,再传递到 File1.txtFile2.txt。也就是在传递过程中,不会有任何的限制和阻挠

  • PropagationFlags.NoPropagateInherit:权限会从 RootFolder 传递到 SubFolder1SubFolder2,但不会传递到 File1.txtFile2.txt

  • PropagationFlags.InheritOnlyRootFolder 本身不会有这个权限,但 SubFolder1SubFolder2File1.txtFile2.txt 可能会继承这个权限。

通过 PropagationFlags,你可以更精细地控制权限是如何在子文件夹和文件之间传播的。

3、疑问点汇总

在进行权限设置的时候,总会会有疑惑,不明白为什么会这样,这里把相关的疑问点记录一下

问题1:文件的重命名是什么权限?

如果我们希望能够设置某一个文件能够进行重命名的操作,那其实我们并不是直接针对文件进行权限设置,而是要设置该文件所在的文件夹本身的权限。该文件夹下,必须拥有 删除原文件名创建新文件名的权限。因为重命名的本质,就是删除源文件,生成一个新文件。

问题2:我给文件夹设置可编辑,设置文件夹下面的文件为完全控制,为什么文件不能重命名

即使你为文件设置了“完全控制”权限,用户在重命名文件时仍需要对目录有足够的权限。重命名文件实际上是对文件所在目录进行修改,包括删除旧文件名和创建新文件名。因此,你需要确保目录具有足够的权限来允许文件的重命名操作。

确保目录权限包括以下内容:

  • 修改权限 (Modify) : 允许修改目录中的内容,包括重命名文件。
  • 删除权限 (Delete) : 允许删除目录中的文件,这也间接允许重命名文件。
  • 创建文件权限 (CreateFiles) : 允许在目录中创建新文件,这通常与重命名操作相关联。

问题3:FileSystemRights为什么枚举值一样?

在Net源码中,我们发现 FileSystemRights.CreateDirectoriesFileSystemRights.AppendData 是一样的,那么是否可以认为他们是可以替换的?

  [Flags]
  public enum FileSystemRights
  {
    ReadData = 1,
    ListDirectory = ReadData, // 0x00000001
    WriteData = 2,
    CreateFiles = WriteData, // 0x00000002
    AppendData = 4,
    CreateDirectories = AppendData, // 0x00000004
    ...
  }

解释

在 .NET 的 FileSystemRights 枚举中,AppendDataCreateDirectories 共享相同的值 (0x00000004)。这在某些权限系统中是常见的设计,背后的原因如下:

1. 值复用的设计逻辑

  • 权限的语义:在文件系统中,某些权限的语义在不同的上下文中是相似的。例如:

    • 在文件的上下文中,AppendData 表示允许在文件末尾追加数据。
    • 在目录的上下文中,AppendData 的语义转变为允许在该目录下创建新条目(如子目录或文件)。因此,CreateDirectories 权限本质上是 AppendData 在目录上下文中的一种特殊表示。
  • 值复用:为了简化权限管理,减少权限位的数量,系统设计者复用了相同的位表示这两种语义相近的操作。这就是为什么在 FileSystemRights 枚举中,AppendDataCreateDirectories 被赋予相同的值。

2. 具体实现

在实际实现中,文件系统会根据操作对象的类型来解释这个权限:

  • 文件: 当操作对象是文件时,值 0x00000004 被解释为允许追加数据 (AppendData)。
  • 目录: 当操作对象是目录时,值 0x00000004 被解释为允许创建子目录 (CreateDirectories)。

3. 兼容性和简化

这种设计使得权限系统更为简洁,因为同一位掩码在不同上下文中可以有不同的解释。这种方式既简化了权限位的定义,又提供了足够的灵活性来描述不同的文件系统操作。

总结

虽然 AppendDataCreateDirectories 在代码中共享相同的值,但它们在不同的上下文中有不同的含义。这是一种系统设计的简化方式,用来处理文件和目录上的权限管理。

4、不同权限的设置组合

1、不允许创建新文件,不允许更改名称,不允许删除文件,可以修改文件里面的内容

Write | ReadAndExecute | ChangePermissions | TakeOwnership | Synchronize
InheritanceFlags=ContainerInherit, ObjectInherit
PropagationFlags=InheritOnly

2、不允许创建新文件,不允许更改名称,允许删除文件,可以修改文件里面的内容

Write | ReadAndExecute | ChangePermissions | TakeOwnership | Synchronize | Delete;
var inheritanceFlags = InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit;
var propagationFlags = PropagationFlags.InheritOnly;

3、不允许创建新文件,不允许更改名称,不允许删除文件,可以修改文件里面的内容

Write | ReadAndExecute | ChangePermissions | TakeOwnership | Synchronize
PropagationFlags=InheritOnly
InheritanceFlags=ObjectInherit

4、可以创建文件,但不能创建文件夹

# 这里只需要给一个CreateFiles 权限就行,
CreateFiles | Synchronize
PropagationFlags=None
InheritanceFlags=None

5、可以创建文件夹,但是不能创建文件

# AppendData 创建文件夹
AppendData | Synchronize
PropagationFlags=None
InheritanceFlags=None

6、不能创建文件夹,可以删除文件夹和文,文件夹和文件不能重命名,可以编辑文件

# 不能创建文件夹,因为这里针对的权限是字节对象
# 可以删除文件夹和文件 因为是作用于 子级容器和子级文件
# 文件夹和文件不能重命名
# 可以编辑文件

Modify | ChangePermissions | TakeOwnership | Synchronize
PropagationFlags=InheritOnly
InheritanceFlags=ContainerInherit, ObjectInherit

C#中对象

参考链接

rootclay.gitbook.io/windows-acc…

learn.microsoft.com/zh-cn/windo…

www.cnblogs.com/cdaniu/p/15…

blog.csdn.net/stevenjoo67…

learn.microsoft.com/en-us/archi…