我创建了一个自托管的 WCF REST 服务(带有 WCF REST Starter Kit Preview 2 中的一些额外内容)。这一切工作正常。
我现在正在尝试向服务添加基本身份验证。但我在 WCF 堆栈中遇到了一些相当大的障碍,这阻止了我这样做。
看来HttpListener
(自托管 WCF 服务在 WCF 堆栈的低级别内部使用)阻止了我插入WWW-Authenticate
自行生成的标头401 Unauthorized
回复。为什么?
如果我忘记了这一点,我可以让身份验证工作WWW-Authenticate
header(微软似乎也这么做了)。但这就是问题所在。如果我不发回WWW-Authenticate
标头,则 Web 浏览器将不会显示其标准“登录”对话框。用户将仅仅面临一个401 Unauthorized
错误页面,无法实际登录。
REST 服务应该可供计算机和人类访问(至少在 GET 请求级别)。因此,我觉得 WCF REST 在这里不符合 REST 的基本部分。有人同意我的观点吗?
有人使用自托管 WCF REST 服务进行基本身份验证吗?如果是这样,你是怎么做到的?
PS:显然,我打算使用不安全的基本身份验证的前提是我也能让 HTTPS/SSL 为我的服务工作。但那是另一回事了。
PPS:我已经尝试过 WCF REST Contrib (http://wcfrestcontrib.codeplex.com/ http://wcfrestcontrib.codeplex.com/)并且有完全相同的问题。该库似乎尚未在自托管场景中进行测试。
Thanks.
不幸的是,我已经确定(通过分析 WCF 参考源代码以及用于 HTTP 会话嗅探的 Fiddler 工具的帮助)这是 WCF 堆栈中的一个错误。
使用 Fiddler,我注意到我的 WCF 服务的行为与使用基本身份验证的任何其他网站不同。
需要明确的是,这是应该发生的事情:
- 浏览器发送
GET
请求时不知道甚至需要密码。
- Web 服务器拒绝请求
401 Unauthorized
状态并包括WWW-Authenticate
标头包含有关可接受的身份验证方法的信息。
- 浏览器提示用户输入凭据。
- 浏览器重新发送
GET
请求并包括适当的Authentication
带有凭据的标头。
- 如果凭据正确,Web 服务器会响应
200 OK
和网页。
如果凭据错误,Web 服务器会响应401 Unauthorized
并包括相同的WWW-Authenticate
它在步骤 #2 中执行的标头。
我的 WCF 服务实际发生的情况是这样的:
- 浏览器发送
GET
请求时不知道甚至需要密码。
- WCF 通知没有
Authentication
请求中的标头并盲目拒绝带有401 Unauthorized
状态并包括WWW-Authenticate
标头。目前为止一切正常。
- 浏览器提示用户输入凭据。还是正常的。
- 浏览器重新发送
GET
请求包括适当的Authentication
header.
- 如果凭据正确,Web 服务器会响应
200 OK
。一切皆好。
但是,如果凭据错误,WCF 会响应403 Forbidden
并且不包含任何附加标头,例如WWW-Authenticate
.
当浏览器获取到403 Forbidden
状态 它不会认为这是一次失败的身份验证尝试。此状态代码旨在通知浏览器它尝试访问的 URL 不受限制。它与身份验证没有任何关系。这会产生可怕的副作用,即当用户错误地输入用户名/密码(并且服务器以 403 拒绝)时,Web 浏览器不会重新提示用户再次输入其凭据。事实上,网络浏览器认为身份验证已成功,因此会为会话的其余部分存储这些凭据!
考虑到这一点,我寻求澄清:
RFC 2617(http://www.faqs.org/rfcs/rfc2617.html#ixzz0eboUfnrl http://www.faqs.org/rfcs/rfc2617.html#ixzz0eboUfnrl)没有在任何地方提到使用403 Forbidden
状态码。事实上,它对此事的实际说法如下:
如果源服务器不希望
接受通过 a 发送的凭据
请求,它应该返回 401
(未经授权)回应。响应
必须包含 WWW-Authenticate 标头
字段至少包含一个
(可能是新的)挑战适用于
所请求的资源。
WCF 两者都不做。它既不正确发送401 Unauthorized
状态码。它也不包括WWW-Authenticate
header.
现在在 WCF 源代码中找到确凿的证据:
我发现在HttpRequestContext
类是一个名为的方法ProcessAuthentication
,其中包含以下内容(摘录):
if (!authenticationSucceeded)
{
SendResponseAndClose(HttpStatusCode.Forbidden);
}
我在很多事情上都为微软辩护,但这是站不住脚的。
幸运的是,我已经让它工作到了“可接受的”水平。这只是意味着,如果用户不小心输入了错误的用户名/密码,那么再次尝试的唯一方法是完全关闭其网络浏览器并重新启动以重试。这一切都是因为 WCF 是not响应失败的身份验证尝试401 Unauthorized
and a WWW-Authenticate
标头按照规范。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)