5

一位同事今天问我如何配置 IIS 7.5 以使用集成的 Windows 身份验证和模拟,用于一个简单的 Intranet 网站,该网站只有静态内容,仅限于 Active Directory 中的特定组(例如,“管理员”)。

事实证明,当经过身份验证的用户无权访问请求资源时,IIS 会发送 HTTP 401 响应。权限被拒绝可能是 NTFS 文件 ACL 或system.webServer/security/authorizationIIS 配置中定义的 ACL 的结果。

所有主流浏览器似乎都将这个 401 解释为最终用户提供了无效的 Windows 用户名/密码凭据,因此提示用户输入他们的用户名/密码。在显示 401 响应正文/内容之前,IE 似乎最多提示 3 次。Chrome 和 Safari 似乎在反复提示用户。

这可能会令最终用户感到困惑,他们不断重复输入有效的 Windows 用户名/密码,但又会再次收到提示。

更好的方法是让 IIS 返回 HTTP 403 而不是 HTTP 401:

403 禁止

服务器理解请求,但拒绝执行。授权将无济于事,并且不应重复请求。

来源:http ://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.4

如何配置 IIS 集成 Windows 身份验证以发送 HTTP 401 登录失败和 HTTP 403 权限被拒绝?

4

1 回答 1

9

什么没有奏效

我尝试了几乎所有 IIS 配置排列,但都没有运气。我玩弄了 Windows 身份验证提供程序设置,例如 NTLM、Negotiate 和 Negotiate:Kerberos。他们似乎都没有成功。这并不奇怪,因为浏览器决定再次尝试身份验证,即使他们可能不应该这样做。

401未经授权

该请求需要用户身份验证。响应必须包含一个 WWW-Authenticate 头字段(第 14.47 节),其中包含适用于所请求资源的质询。客户端可以使用合适的授权头域重复请求(第 14.8 节)。如果请求已包含授权凭证,则 401 响应指示已拒绝对这些凭证的授权。

来源:http ://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.4.2

什么起作用了

我决定利用一些肮脏的 ASP.NET 来解决这个问题。下面借助服务器上的几个文本文件和 ASP.NET 动态编译实现响应重写。(我以前从未使用过动态编译,但是对于静态站点来说,编译似乎有点过头了。)

下面的 Global.asax 文件挂钩 EndRequest 事件,如果用户成功通过身份验证为 Windows 用户,则将 HTTP 401 响应重写为 HTTP 403,但是由于某些其他原因,请求被拒绝(我认为原因必须是授权失败)。

web.config 文件包含通过 ASP.NET 管道路由所有请求的条目,并拒绝任何不是“Sales”Windows 组成员的经过身份验证的用户的访问。

此解决方案假定您有一个在 IIS 集成管道模式(即非经典模式)下运行的应用程序,您启用了 Windows 身份验证,并禁用了所有其他身份验证方案。

/全球.asax:

<Script language="C#" runat="server">
     void Application_EndRequest() {
          // rewrite HTTP 401s to HTTP 403s if the user is authenticated using 
            // integrated Windows auth with impersonation, but, 
            // the user lacks permissions to the requested URL
            if (Context.User != null && 
                    Context.User.Identity != null &&
                        Context.User.Identity.IsAuthenticated &&
                            Context.User is System.Security.Principal.WindowsPrincipal && 
                                Context.Response.StatusCode == 401) 
            {
                Context.Response.Clear();
                Context.Response.StatusCode = 403;
            }
        }
</script>

/web.config:

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <system.webServer>
        <security>
            <authorization>
                <remove users="*" roles="" verbs="" />
                <add accessType="Allow" roles="Sales" />
            </authorization>
        </security>
      <modules runAllManagedModulesForAllRequests="true" />
    </system.webServer>
</configuration>

为了将来参考,我创建了一个 Gist @ https://gist.github.com/steve-jansen/6234700

于 2013-08-14T20:27:42.820 回答