Web Deploy 高级应用:自动设置 ACL
2011-01-04 19:39 Nana's Lich 阅读(6037) 评论(0) 编辑 收藏 举报引言
前一篇文章中讲解了 Web Deploy 技术的简单使用,以及避免已有的 ACL 设置被清除的办法。
而这一次我将会讲解在使用 Visual Studio (Express) 进行一键发布时自动完成 ACL 设置的办法。
原理
在解决上一篇文章的问题的过程中中提到了 MSBuild 指令的使用,稍加思考的话并不难得出这样一个结论:
Web Deploy 设置 ACL 的具体方式也是通过 MSBuild 操控的。
而如果我们调查了 Microsoft.Web.Publishing.targets 的话,就会发现这样的一些指令:
<!--Make sure the by default Networkservice/AppPoolIdentity have read permissing to the fodler--> <MsDeploySourceManifest Include="setAcl" Condition="$(IncludeSetAclProviderOnDestination)"> <Path>$(_MSDeployDirPath_FullPath)</Path> <setAclResourceType>Directory</setAclResourceType> <AdditionalProviderSettings>setAclResourceType</AdditionalProviderSettings> </MsDeploySourceManifest> <!--Make sure the by default anonymousAuthenticationUser have read permissing to the fodler so MIME type files will work--> <MsDeploySourceManifest Include="setAcl" Condition="$(IncludeSetAclProviderOnDestination)"> <Path>$(_MSDeployDirPath_FullPath)</Path> <setAclUser>anonymousAuthenticationUser</setAclUser> <setAclResourceType>Directory</setAclResourceType> <AdditionalProviderSettings>setAclUser;setAclResourceType</AdditionalProviderSettings> </MsDeploySourceManifest> <!--Additionally if App_Data Need to be ReadWrite--> <MsDeploySourceManifest Include="setAcl" Condition="$(IncludeSetAclProviderOnDestination) And $(MarkApp_DataWritableOnDestination) And Exists('$(_MSDeployDirPath_FullPath)\App_Data')"> <Path>$(_MSDeployDirPath_FullPath)\App_Data</Path> <setAclAccess>Write</setAclAccess> <setAclResourceType>Directory</setAclResourceType> <AdditionalProviderSettings>setAclResourceType;setAclAccess</AdditionalProviderSettings> </MsDeploySourceManifest>
其中 XML 元素名称 MsDeploySourceManifest 表示了它会在 Web Deploy 的程序清单(Manifest)中产生一个对应的指令;
Include="setAcl" 指示了将要产生一个 setAcl 指令,顾名思义,它是用来设置 ACL 的;
Condition="..." 表示这条指令将在特定的条件下产生,由于其中涉及到了大量的其它 MSBuild 指令,现在就详细讲解似乎有点早,为了不让大家被一大堆概念搞得晕头转向,这部分放后面说;
<Path>$(_MSDeployDirPath_FullPath)</Path> 指示了将要向网站程序的根目录设置 ACL,$(_MSDeployDirPath_FullPath) 表示了 Web Deploy 的目标路径(它的实际含义其实是有些区别的,同样放后面);
<setAclAccess>Write</setAclAccess> 指示了赋予写操作的权限,如果只需要读操作权限,可以省略掉;
<setAclUser>anonymousAuthenticationUser</setAclUser> 指示了将要向谁赋予操作权限,anonymousAuthenticationUser 表示匿名访问者,如果希望向应用程序池的身份标识赋予操作权限,就可以省略掉;
<setAclResourceType>Directory</setAclResourceType> 表示将要向一个目录设置 ACL,可以省略掉;
<AdditionalProviderSettings>setAclResourceType</AdditionalProviderSettings> 表示启用 setAclResourceType 选项,如果其中不包含任何选项,就同样可以省略。
综合来说,上面所列出的这些指令说明了在默认情况下,Web Deploy 会自动赋予匿名用户及应用程序池对网站目录的读操作权限(省略时)、赋予应用程序池对数据库目录的写操作权限(看来这里不需要写成“Read,Write”,是个有意思的现象)
操练起来
如果要给应用程序池指派其它的操作权限——比方说完全控制网站目录,也需要使用像是这样的指令。
不过实际上在 *.wpp.targets 里面添加这样的 MSBuild 指令的时候是有些技术细节需要注意的,比方说这些指令应该添加在什么地方、怎么样让它们被执行。
就以这次的“完全控制”来说,首先自然要依葫芦画瓢地写一段指令,大概会是这样:
<MsDeploySourceManifest Include="setAcl"> <Path>$(_MSDeployDirPath_FullPath)</Path> <setAclAccess>FullControl</setAclAccess> <AdditionalProviderSettings>setAclAccess</AdditionalProviderSettings> </MsDeploySourceManifest>
注:由于 setAclResourceType 的默认值就是 Directory,所以可省略掉。
本质上说,MsDeploySourceManifest 是一种自定义的指令物件,依赖于 MSBuild 的可扩展性发挥作用。
而这种指令物件必须放置在<ItemGroup/>指令中,然后为了能在合适的时机执行这些指令,还需要把它们放进一个命名的<Target/>指令中,结果大概就是这样:
<Target Name="MySetAcl"> <ItemGroup> <MsDeploySourceManifest Include="setAcl"> <Path>$(_MSDeployDirPath_FullPath)</Path> <setAclAccess>FullControl</setAclAccess> <AdditionalProviderSettings>setAclAccess</AdditionalProviderSettings> </MsDeploySourceManifest> </ItemGroup> </Target>
而指定了名称之后,还需要在适当的生成任务中调用它,才能真正地发挥作用。
如果搜索关于 Web Deploy 和 setAcl 的文章的话,可能会发现有些文章建议在 AfterAddContentPathToSourceManifest 事件中调用这个自定义生成任务,但是实际上这样做的结果是自定义的 setAcl 指令会添加到 Web Deploy 自动生成的 setAcl 指令之前,导致我们设置的 ACL 被覆盖而失去作用。
对于这个问题,国外有同样研究自动设置 ACL 的人,给出的建议是:把调用添加在 AfterAddIisSettingAndFileContentsToSourceManifest 事件中,也就是这样:
<AfterAddIisSettingAndFileContentsToSourceManifest> MySetAcl; </AfterAddIisSettingAndFileContentsToSourceManifest>
到现在为止,我们的 *.wpp.targets 看起来差不多就是这样了:
<?xml version="1.0" encoding="utf-8" ?> <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <PropertyGroup> <AfterAddIisSettingAndFileContentsToSourceManifest> MySetAcl; </AfterAddIisSettingAndFileContentsToSourceManifest> </PropertyGroup> <Target Name="MySetAcl"> <ItemGroup> <MsDeploySourceManifest Include="setAcl"> <Path>$(_MSDeployDirPath_FullPath)</Path> <setAclAccess>FullControl</setAclAccess> <AdditionalProviderSettings>setAclAccess</AdditionalProviderSettings> </MsDeploySourceManifest> </ItemGroup> </Target> </Project>
而到这个程度,就已经可以达到“向应用程序池赋予对应用程序目录的完全控制权限”的目的了。
在进行发布之前请注意保存 *.wpp.targets,并重新加载项目。
补充说明
有两个技术细节在这里补充一下:
- 如果把 IncludeSetAclProviderOnDestination 设置为 False 的话,是可以在 AfterAddContentPathToSourceManifest 事件调用我们的自定义任务的,但是这样做到话 Web Deploy 也不会自动为匿名访问者赋予读取权限,需要我们手动添加相关的指令,所以不推荐这样做。
- 在起草本文的过程中参考了 http://leethams.com/blog/?p=102,但是本文省略掉了 AfterAddIisSettingAndFileContentsToSourceManifest 事件的条件属性,原因是:从 *.wpp.targets 导入的指令的执行顺序比较靠前,这个时候绝大部分和 Web Deploy 有关的 MSBuild 属性(包括事件)的内容都为空,条件判断的结果一定为真,没有实际意义。
另外由于实际写出来之后文章内容比预期得要长,所以为了让大家阅读起来方便一些,关于“自定义子目录的 ACL”的部分就要放到后面的部分中了,敬请期待。