最近公司有些业务用到了 Windows下面的文件权限设置。所以针对权限系统相关的知识做一下总结和分享,因为windows授权管理系统非常的复杂,特别是在权限的传播,影响的是文件夹还是文件层面。
1、继承和传播标志的快速预览
下面是微软的msdn上找的一篇文章,讲述了访问规则的设置问题。
每个访问规则要么是显式的,要么是继承的。其中
- 显示规则:在对象上执行显示操作,添加到对象上的规则
- 继承规则:来自于父容器
向容器添加新的显式规则时,您可以指定两组标志:一组用于继承,一组用于传播。
继承标志(InheritanceFlags):
- 容器继承(CI):指定容器继承的规则将适用于当前对象的子容器
- 对象继承(OI):对象继承规则将适用于子叶对象
- 无:权限只作用于当前对象,不会传递给它的子对象,不再向下作用了。
传播标志(PropagationFlags)
- 仅继承(IO):仅继承标志的意思是该规则仅适用于子对象,而不适用于对象本身
- 不传播继承(NP):它会影响子对象,但不会影响孙对象
- 无:没有特殊的传播规则,权限会正常继承到所有子对象。也就是不加入任何的拦截,0拦截。
下面来展示继承和传播标志如何影响容器,我们目前针对最顶部的文件夹,进行权限设置。
我从上至下,从左往右的依次解释这张图
1、WIndows名称为:只有该文件夹 (InheritanceFlags.None, PropagationFlags.None)
图中没有设置任何的传播,也就是 InheritanceFlags.None, PropagationFlags.None,权限仅仅是设置在当前文件夹,并没有往下传播。
- 如果在此文件夹设置了访问权限。那么,我们只能看到C本身,当我们打开"C"的时候,看不到任何的东西,因为我们的访问权限,并没有传递到下面
- 如果在此文件夹设置完全访问权限,发现自己也是什么也做不了,无法删除文件夹,无法编辑
图中设置了继承的标志为 容器继承(CI),但是没有设置传播的标志,所以针对C上面的权限,CC,GC这两个文件夹能够看得到,但是CO,GO这两个文件,就看不到了
2、WIndows名称为: 此文件夹和子文件夹(InheritanceFlags.ContainerInherit, PropagationFlags.None)
图中设置了继承的标志为 对象继承(OI),没有设置传播的标志,也就是能够一直传播下去。仅仅对文件有权限。
3、WIndows名称为: 此文件夹和文件(InheritanceFlags.ObjectInherit, PropagationFlags.None)
- 如果设置的是访问权限:则只能看到C下面的CO文件,而无法看到CC下面的GO文件
图中设置了继承标志:容器继承(CI),对象继承(OI),设置了传播标志:仅继承(IO)。也就是当对C进行设置的时候,下面的文件夹,和子文件都能收到影响。仅继承(IO) 这个标志,指的是子级,不包括自己。
4、WIndows名称为: 仅子文件夹和文件(InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.InheritOnly)
- 如果在C进行设置访问权限,那么,无法直接看到C这个文件夹,而且也无法查看CO文件。但是可以进去到CC文件夹中,看到GC文件夹和GO文件
图中设置了继承标志:容器继承(CI) 和传播标志:不传播继承(NP)。 意思是影响到当前文件夹和子级的文件夹,
5、Windows名称为:此文件夹和子文件夹(InheritanceFlags.ContainerInherit,PropagationFlags.NoPropagateInherit)
-
如果给当前对象设置权限,那么只会影响到C和CC。如果设置了访问权限,那么,只能看到C,以及CC文件夹。打开CC文件夹后,什么都不能看到。
-
仅仅设置了访问权限后,在C文件夹下,只能看,其他的一切,都做不到
-
如果设置C为完全控制权限,在C下面创建文件夹是OK的。但是在创建文件的时候,没有任何的反应,其实已经创建成功了,只是看不到文件而已。如果这个时候,再次创建文件,则会提示报错,报错提示为:
图中设置了继承标志:对象继承(OI) 和 传播标志:不传播继承(NP)。只能作用于当前文件和子文件。
6、Windows名称为:此文件夹和文件(InheritanceFlags.ObjectInherit,PropagationFlags.NoPropagateInherit)
- 如果设置的访问权限:那么只能看到CO文件
- 如果设置的操作权限:则无法创建文件夹
图中设置了继承标志:容器继承(CI),对象继承(OI) 和 传播标志:不传播继承(NP)。
只能作用于当前文件夹和当前文件
7、Windows名称为:此文件夹和文件(InheritanceFlags.ContainerInherit|InheritanceFlags.ObjectInherit,PropagationFlags.NoPropagateInherit)
- 当前设置了完全控制权限,无法修改C的名称,但是可以删除C,只是删除C的时候,C文件夹和CC文件夹不会受到影响,CO这些子文件则会被删除。
- 可以新增CC子文件夹,但是如果CC文件夹里面,有GC和CO,则不能删除
- 可以重命名CC文件夹
8、Windows对应的名称为: 此文件夹和子文件夹和文件
图中设置了继承标志:容器继承(CI) ,对象继承(OI)
InheritanceFlags : InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit
PropagationFlags : PropagationFlags.None
这种方式的设置,是影响面最广的
9、Windows对应的名称为: 此文件夹和子文件夹和文件
图中设置了继承标志:容器继承(CI) , 传播标志:仅继承(IO)
InheritanceFlags : InheritanceFlags.ContainerInherit
PropagationFlags : PropagationFlags.InheritOnly
-
如果设置为访问权限,则C不可见,而能直接打开CC和GC这些子文件夹
-
如果设置为可编辑:则C不可见,可以在CC文件夹下新增文件夹,GC文件夹下新增文件夹
10、Windows对应的名称为: 只有文件
图中设置了继承标志:对象继承(OI) , 传播标志:仅继承(IO)
InheritanceFlags : InheritanceFlags.ObjectInherit
PropagationFlags : PropagationFlags.InheritOnly
- 设置C的完全控制权限,然后再额外加上文件的访问权限。我们就能做到,用户只能针对文件进行写入,而无法做其他的操作
11、Windows对应的名称为: 只有子文件夹
图中设置了继承标志:容器继承(CI) , 传播标志:仅继承(IO),不传播继承(NP)
InheritanceFlags : InheritanceFlags.ContainerInherit
PropagationFlags : PropagationFlags.InheritOnly | PropagationFlags.NoPropagateInherit
- 如果设置了访问权限,那么只能打开CC文件夹,且看不到任何的东西
- 一般的业务场景都是 控制CC文件夹的删除,或者更改权限
12、Windows对应的名称为: 只有子文件
图中设置了继承标志:对象继承(OI) , 传播标志:仅继承(IO),不传播继承(NP)
InheritanceFlags : InheritanceFlags.ObjectInherit
PropagationFlags : PropagationFlags.InheritOnly | PropagationFlags.NoPropagateInherit
- 只能控制该文件夹的文件
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这个文件夹有这个权限,里面的Work、Personal以及Report.docx和Photos.jpg都不会有这个权限。 -
InheritanceFlags.ContainerInherit:如果你选择了ContainerInherit,那么Documents的权限会传递给Work和Personal这些子文件夹,但Report.docx和Photos.jpg这些文件不会继承。 -
InheritanceFlags.ObjectInherit:如果你选择了ObjectInherit,那么Documents的权限会传递给Report.docx和Photos.jpg这些文件,但Work和Personal这些子文件夹不会继承。
这样,你可以根据需要决定权限是否传递给文件夹、文件,还是都不传递。
(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 的文件夹,里面有子文件夹 SubFolder1 和 SubFolder2,每个子文件夹里又有一些文件:现在针对 RootFolder设置一些权限。
RootFolder
├── SubFolder1
│ └── File1.txt
└── SubFolder2
└── File2.txt
以下可以设置的规则
-
PropagationFlags.None:权限会从RootFolder传递到SubFolder1和SubFolder2,再传递到File1.txt和File2.txt。也就是在传递过程中,不会有任何的限制和阻挠 -
PropagationFlags.NoPropagateInherit:权限会从RootFolder传递到SubFolder1和SubFolder2,但不会传递到File1.txt和File2.txt。 -
PropagationFlags.InheritOnly:RootFolder本身不会有这个权限,但SubFolder1、SubFolder2、File1.txt和File2.txt可能会继承这个权限。
通过 PropagationFlags,你可以更精细地控制权限是如何在子文件夹和文件之间传播的。
3、疑问点汇总
在进行权限设置的时候,总会会有疑惑,不明白为什么会这样,这里把相关的疑问点记录一下
问题1:文件的重命名是什么权限?
如果我们希望能够设置某一个文件能够进行重命名的操作,那其实我们并不是直接针对文件进行权限设置,而是要设置该文件所在的文件夹本身的权限。该文件夹下,必须拥有 删除原文件名并创建新文件名的权限。因为重命名的本质,就是删除源文件,生成一个新文件。
问题2:我给文件夹设置可编辑,设置文件夹下面的文件为完全控制,为什么文件不能重命名
即使你为文件设置了“完全控制”权限,用户在重命名文件时仍需要对目录有足够的权限。重命名文件实际上是对文件所在目录进行修改,包括删除旧文件名和创建新文件名。因此,你需要确保目录具有足够的权限来允许文件的重命名操作。
确保目录权限包括以下内容:
- 修改权限 (Modify) : 允许修改目录中的内容,包括重命名文件。
- 删除权限 (Delete) : 允许删除目录中的文件,这也间接允许重命名文件。
- 创建文件权限 (CreateFiles) : 允许在目录中创建新文件,这通常与重命名操作相关联。
问题3:FileSystemRights为什么枚举值一样?
在Net源码中,我们发现 FileSystemRights.CreateDirectories 和 FileSystemRights.AppendData 是一样的,那么是否可以认为他们是可以替换的?
[Flags]
public enum FileSystemRights
{
ReadData = 1,
ListDirectory = ReadData, // 0x00000001
WriteData = 2,
CreateFiles = WriteData, // 0x00000002
AppendData = 4,
CreateDirectories = AppendData, // 0x00000004
...
}
解释
在 .NET 的 FileSystemRights 枚举中,AppendData 和 CreateDirectories 共享相同的值 (0x00000004)。这在某些权限系统中是常见的设计,背后的原因如下:
1. 值复用的设计逻辑
-
权限的语义:在文件系统中,某些权限的语义在不同的上下文中是相似的。例如:
- 在文件的上下文中,
AppendData表示允许在文件末尾追加数据。 - 在目录的上下文中,
AppendData的语义转变为允许在该目录下创建新条目(如子目录或文件)。因此,CreateDirectories权限本质上是AppendData在目录上下文中的一种特殊表示。
- 在文件的上下文中,
-
值复用:为了简化权限管理,减少权限位的数量,系统设计者复用了相同的位表示这两种语义相近的操作。这就是为什么在
FileSystemRights枚举中,AppendData和CreateDirectories被赋予相同的值。
2. 具体实现
在实际实现中,文件系统会根据操作对象的类型来解释这个权限:
- 文件: 当操作对象是文件时,值
0x00000004被解释为允许追加数据 (AppendData)。 - 目录: 当操作对象是目录时,值
0x00000004被解释为允许创建子目录 (CreateDirectories)。
3. 兼容性和简化
这种设计使得权限系统更为简洁,因为同一位掩码在不同上下文中可以有不同的解释。这种方式既简化了权限位的定义,又提供了足够的灵活性来描述不同的文件系统操作。
总结
虽然 AppendData 和 CreateDirectories 在代码中共享相同的值,但它们在不同的上下文中有不同的含义。这是一种系统设计的简化方式,用来处理文件和目录上的权限管理。
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…