在IIS添加网站(假设站点为xxx.yyy.com,本例假设IIS版本为7.5或以上),如果采用IIS默认配置,会在创建站点同时创建相应同名的“应用程序池”(也是xxx.yyy.com)。
在这种默认的情况下,连接的用户是通过身份验证后传递而来的,其最终用户凭据为“匿名身份验证”当中的“特定用户” IUSR,访问目录资源时就会验证IUSR的权限。默认配置如下图所示:
添加完站点后不作其它操作,直接访问 http://xxx.yyy.com/,会出现授权问题。
远程(即不在与IIS服务器同个机子上访问)访问出错情形:401 - 未授权: 由于凭据无效,访问被拒绝。
本机(与IIS服务器同个机子上访问)访问的错误信息:HTTP 错误 401.3 - Unauthorized。由于 Web 服务器上此资源的访问控制列表(ACL)配置或加密设置,您无权查看此目录或页面。
远程访问与本机访问出现不同错误信息,但都是同一个错误。这个是源于IIS默认配置中httpErrors项的errorMode设置为DetailedLocalOnly。它表示如果站点出错时,如果是本机访问,则输出详细错误,如果是远程访问,则隐藏详细错误。也可以直接配置为“Detailed”,此时不管本机还是远程,访问出错都显示详细错误(但如果是真实的服务器,为安全性起见,如果需要,建议配置为DetailedLocalOnly)
出错的原因很明显,是权限问题。在默认配置下,访问目录资源时就会验证IUSR的权限。为解决IUSR的权限,直接添加目录,给予IUSR账户的读取权限:
之后再次访问,网站可以正常访问了(但这不是最终正确的结果,因为此时,站点根目录里还没有web.config文件)。
在站点功能视图中进行一些操作(如“处理器映射”、“默认文档”、“错误页”),使根目录产生web.config文件。本例进行“默认文档”,删除不必要的默认文档项如"Default.htm",产生的web.config。
然后再次访问http://xxx.yyy.com,会再次报错。(如果没有报错,是应用程序池的处理时有缓存操作,可以先重启xxx.yyy.com应用程序池。这种暂时不报错的现象往往出现在:先产生了web.config配置文件,然后再添加IUSR权限。之前的操作是先添加IUSR权限,再产生web.config,所以现象更明显)
远程访问错误信息:500 - 内部服务器错误。您查找的资源存在问题,因而无法显示。
本机访问错误信息:HTTP 错误 500.19 - Internal Server Error。无法访问请求的页面,因为该页的相关配置数据无效。由于权限不足而无法读取配置文件
IIS对应的站点日志文件里也记录了相应的错误信息:(如401.3与500.19错误会分别显示“401 3”与“500 19”)
本机访问出错信息当中的“链接和更多信息”,点击可定位到https://learn.microsoft.com/zh-CN/troubleshoot/developer/webapps/iis/health-diagnostic-performance/http-error-500-19-webpage#hresult-code-0x80070005
该页面显示了该错误的相关解决方案。根据该解决方案,添加wwwroot目录的IIS_IUSRS组的读取权限,即可解决web.config权限问题导致的500.19问题(至于该错误为什么产生的真实原因,后面详解)
注意:在当前默认配置下(“连接为”-通过身份验证传递),对于“匿名身份验证”-特定用户,将其中的IUSR换为其它自定义的计算机用户(不管该用户属于哪个用户组,哪怕是Administrators组),也会出现同样的500问题,以及需要上边同样的解决方法。
如果需要,可以参见http客户端错误相应文件目录(C:\inetpub\custerr\zh-CN\),该目录汇集了所有常见http错误的一些信息内容显示,如:
另外,如果站点整合PHP时,如果是PHP目录权限的问题,则访问后也会出现500错误。
远程访问时出错信息如下:远程访问错误信息:500 - 内部服务器错误。您查找的资源存在问题,因而无法显示。
本机访问时出错信息如下:HTTP 错误 500.0 - Internal Server Error。 对找不到的文件启用文件监视
为什么IIS_IUSRS可以解决有web.config文件而不出错。下图给出了详细解释:
上图表明: “连接为”的两种方式,对于web.config权限处理是有影响的。
当“连接为”-特定用户,则站点根目录有特定用户的读取权限时:
有没有web.config文件,处理html都不会出现web.config的权限问题。
当“连接为”-应用程序用户(通过身份验证)时:
则站点根目录有特定用户的读取权限时:如果没有web.config文件,则处理html不会出现权限问题。如果有web.config文件,站点根目录只有特定用户读取权限时,会出现web.config权限问题,需要添加应用程序池标识(如通用的IIS_IUSRS)的读取权限到该站点根目录来解决问题。
应用程序池“标识”可通过站点的 应用程序池-高级设置-标识 进行设置,默认为ApplicationPoolIdentity。
应用程序池“标识”的设置中,有“内置账户”与“自定义账户”两种。
其中“内置账户”又分四种:LocalSerivce、NetworkService、LocalSystem、ApplicationPoolIdentity,自定义账户则是本地账户(通常创建属于IIS_IUSRS组的用户,但嫌弃权限大,也可以改为Guests组)。
但不管如何指定应用程序池的“标识”,其可以通用的权限账户为:IIS_IUSRS以及IIS AppPool\xxx.yyy.com。
任何被设置为应用程序池“标识”的账户(如LocalService或自定义的web_xxx_yyy_com用户),都“拥有”应用程序池默认标识组IIS_IUSRS类似的功能权限(能够执行PHP模块与处理web.config)
所以当设置PHP目录的读取与执行权限以及设置web.config读取权限(设置到web.config的所在目录),可以通用IIS_IUSRS与IIS AppPool\xxx.yyy.com,于是,可以给之前默认设置下出现500.19的站点,
给予根目录IIS_IUSRS读取权限(或IIS AppPool\xxx.yyy.com读取权限)。
一般PHP与IIS搭建时的权限设置,可以有通用的设置:
归纳表格:
连接为 | 匿名身份验证凭据 | 应用程序池标识 | web根目录读权限 | PHP目录读取与执行权限 | 说明 | |
---|---|---|---|---|---|---|
方式一 | 传递身份验证 | 特定用户:IUSR | 内置账户:ApplicationPool | IUSR+IIS_IUSRS | IIS_IUSRS | “连接为”设置为“传递身份验证”,web根目录需设置该连接(用户)的读取权限,也必须包含应用程序池标识(用户)的读取权限。因为匿名身份验证设置为特定用户:IUSR(不属于应用程序池标识),因此web根目录需要另外添加应用程序池标识(用户)的读取权限。此时的应用程序池标识(用户):ApplicationPool(即IIS AppPool\xxx.yyy.com),属于IISIUSRS组,故再添加IIS_IUSRS或IIS AppPool\xxx.yyy.com的读取权限都可以。 |
方式七 | 传递身份验证 | 特定用户:IUSR | 内置账户:ApplicationPool | everyone账户 | everyone账户 | 同方式一。针对普通电脑本地测试,使用everyone可以替代IUSR+IIS_IUSRS及IIS_IUSRS。 |
方式三 | 传递身份验证 | 应用程序池标识 | 内置账户:ApplicationPool | IIS AppPool\xxx.yyy.com | IIS_IUSRS | “连接为”设置为“传递身份验证”,web根目录需设置该连接(用户)的读取权限,也必须包含应用程序池标识(用户)的读取权限。因为匿名身份验证设置了该连接(同时)为应用程序池标识(用户):ApplicationPool(即IIS AppPool\xxx.yyy.com),因此web根目录直接添加该连接(用户)AppPool\xxx.yyy.com的读取权限即可。 |
方式二 | 传递身份验证 | 应用程序池标识 | 内置账户:ApplicationPool | IIS_IUSRS | IIS_IUSRS | 同方式三。由于IIS AppPool\xxx.yyy.com标识(用户)属于IIS_IUSRS组,所以对web根目录添加IIS_IUSRS读取权限也可以。 |
方式六 | 传递身份验证 | 应用程序池标识 | 内置账户:LocalSystem | 无需设置 | 无需设置 | 同方式三。针对普通电脑本地测试,因为匿名身份验证设置了该连接(同时)为应用程序池标识(用户):LocalSystem(有超级权限),在此情形下web根目录即使不设置,都能自动拥有LocalSystem的读取权限。 |
方式五 | 传递身份验证 | 特定用户:web_xxx_yyy_com | 自定义账户:web_xxx_yyy_com | web_xxx_yyy_com(需先创建用户) | IIS_IUSRS | “连接为”设置为“传递身份验证”,web根目录需设置该连接(用户)的读取权限,也必须包含应用程序池标识(用户)的读取权限。因为匿名身份验证设置的特定用户(web_xxx_yyy_com)属于应用程序池标识(自定义账户),导致连接(用户)同时也是应用程序池标识,因此web根目录直接添加web_xxx_yyy_com的读取权限即可。 |
方式四 | 特定用户:web_xxx_yyy_com | 特定用户:IUSR | 内置账户:ApplicationPool | web_xxx_yyy_com(需先创建用户) | IIS_IUSRS |
至此,关于PHP+IIS7.X以及的搭建后权限问题解决是没有问答的(这里以读取权限为例子,至于写入权限,根据"连接为”的最终用户相应指定即可)。
不过如果是单纯的PHP站点,首先应该在站点的应用程序池的“基本设置里”,应该将其“.NET Framework版本””修改为“无托管代码”,以排除asp.net权限方面的干扰,防止asp.net相关的“/”应用程序中的服务器错误。
否则一旦出现“/”应用程序中的服务器错误,就要另到:C:\Windows\Microsoft.NET\Framework64\.NET版本号\Temporary ASP.NET Files 设置另外ASP.NET相关的读取与写入权限了。
——