自托管 WCF REST 服务和基本身份验证
我创建了一个自托管的 WCF REST 服务(带有 WCF REST Starter Kit Preview 2 中的一些额外内容)。这一切工作正常。
我现在正在尝试向服务添加基本身份验证。但我在 WCF 堆栈中遇到了一些相当大的障碍,这阻止了我这样做。
看来 HttpListener
(自托管 WCF 服务在 WCF 堆栈中的低级别内部使用)正在阻止我尝试在自行生成的 401 Unauthorized
响应。为什么?
如果我忘记了这个 WWW-Authenticate
标头(微软似乎也这样做了),我就可以让身份验证工作。但这就是问题所在。如果我不发回 WWW-Authenticate
标头,则 Web 浏览器将不会显示其标准“登录”对话框。用户只会面临 401 Unauthorized
错误页面,而无法实际登录。
REST 服务应该可供计算机和人类访问(至少在 GET 请求级别)。因此,我觉得 WCF REST 在这里并不符合 REST 的基本部分。有人同意我的观点吗?
有人使用自托管 WCF REST 服务进行基本身份验证吗?如果是这样,你是怎么做到的?
PS:显然,我打算使用不安全的基本身份验证的前提是我也能让 HTTPS/SSL 为我的服务工作。但那是另一回事了。
PPS:我已经尝试过 WCF REST Contrib (http://wcfrestcontrib.codeplex.com/)有完全相同的问题。该库似乎尚未在自托管场景中进行测试。
谢谢。
I've created a self-hosted WCF REST service (with some extra's from WCF REST Starter Kit Preview 2). This is all working fine.
I'm now trying to add Basic authentication to the service. But I'm hitting some rather large roadblocks in the WCF stack which is preventing me from doing this.
It appears that the HttpListener
(which self-hosted WCF services use internally at a low level in the WCF stack) is blocking my attempts to insert a WWW-Authenticate
header on a self-generated 401 Unauthorized
response. Why?
I can get the authentication working if I forget about this WWW-Authenticate
header (which it seems Microsoft did as well). But that's the issue. If I don't send back a WWW-Authenticate
header then the web browser won't display its standard "logon" dialog. The user will merely be faced with a 401 Unauthorized
error page with no way to actually log on.
REST services should be accessible to both computers and humans (well at least on the GET request level). Therefore, I feel that WCF REST is not complying with a fundamental part of REST here. Does anyone agree with me?
Has anyone got Basic authentication working with a self-hosted WCF REST service? If so, how did you do it?
PS: Obviously my intentions to use unsecure Basic authentication are on the premise that I'd also get HTTPS/SSL working for my service too. But that's another matter.
PPS: I've tried WCF REST Contrib (http://wcfrestcontrib.codeplex.com/) and that has exactly the same issue. It appears this library has not been tested in self-hosted scenarios.
Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
不幸的是,我已经确定(通过分析 WCF 参考源代码以及用于 HTTP 会话嗅探的 Fiddler 工具的帮助)这是 WCF 堆栈中的一个错误。
使用 Fiddler,我注意到我的 WCF 服务的行为与使用基本身份验证的任何其他网站不同。
需要明确的是,这是应该发生的情况:
GET
请求,甚至不知道需要密码。401 Unauthorized
的请求,并包含一个WWW-Authenticate
标头,其中包含有关可接受的身份验证方法的信息。GET
请求,并包含适当的Authentication
标头和凭据。200 OK
和网页。如果凭据错误,Web 服务器将响应
401 Unauthorized
并包含与步骤 #2 中相同的WWW-Authenticate
标头。我的 WCF 服务实际发生的情况是这样的:
GET
请求,甚至不知道需要密码。Authentication
标头,并盲目拒绝状态为401 Unauthorized
的请求,并包含WWW-Authenticate
标头。目前为止一切正常。Authentication
标头的GET
请求。200 OK
。一切都很好。但是,如果凭据错误,WCF 将响应
403 Forbidden
,并且不包含任何其他标头,例如WWW-Authenticate
。当浏览器获得
403 Forbidden
状态时,它不会认为这是一次失败的身份验证尝试。此状态代码旨在通知浏览器它尝试访问的 URL 不受限制。它与身份验证没有任何关系。这会产生可怕的副作用,即当用户错误地输入用户名/密码(并且服务器以 403 拒绝)时,Web 浏览器不会重新提示用户再次输入凭据。事实上,网络浏览器认为身份验证已成功,因此会为会话的其余部分存储这些凭据!考虑到这一点,我寻求澄清:
RFC 2617 (http://www.faqs .org/rfcs/rfc2617.html#ixzz0eboUfnrl)没有在任何地方提到
403 Forbidden
状态代码的使用。事实上,它对此事的实际说法如下:WCF 两者都不做。它既不能正确发送
401 Unauthorized
状态代码。它也不包含WWW-Authenticate
标头。现在在 WCF 源代码中找到确凿的证据:
我发现在
HttpRequestContext
类中有一个名为ProcessAuthentication
的方法,其中包含以下内容(摘录):我捍卫 Microsoft在很多事情上,但这是站不住脚的。
幸运的是,我已经让它工作到了“可接受的”水平。这只是意味着,如果用户不小心输入了错误的用户名/密码,那么再次尝试的唯一方法是完全关闭其网络浏览器并重新启动以重试。所有这些都是因为 WCF 没有按照规范使用
401 Unauthorized
和WWW-Authenticate
标头响应失败的身份验证尝试。Unfortunately I have determined (by analysing the WCF reference source code and the help of the Fiddler tool for HTTP session sniffing) that this is a bug in the WCF stack.
Using Fiddler, I noticed that my WCF service was behaving unlike any other web site which uses Basic authentication.
To be clear, this is what SHOULD happen:
GET
request with no knowledge that a password is even needed.401 Unauthorized
status and includes aWWW-Authenticate
header containing information about acceptable authentication methods.GET
request and includes appropriateAuthentication
header with the credentials.200 OK
and the web page.If the credentials were wrong, the web server responds with
401 Unauthorized
and includes the sameWWW-Authenticate
header that it did in Step #2.What was ACTUALLY happening with my WCF service was this:
GET
request with no knowledge that a password is even needed.Authentication
header in the request and blindly rejects request with a401 Unauthorized
status and includes aWWW-Authenticate
header. All normal so far.GET
request including the appropriateAuthentication
header.200 OK
. All is fine.If the credentials were wrong however, WCF responds with
403 Forbidden
and does not include any additional headers such asWWW-Authenticate
.When the browser gets the
403 Forbidden
status it does not perceive this to be a failed authentication attempt. This status code is intended to inform the browser that the URL it tried to access is off limits. It doesn't relate to authentication in any way. This has the terrible side affect that when the user types their username/password incorrectly (and the server rejects with 403) then the web browser doesn't reprompt the user to type their credentials again. In fact the web browser believes authentication has succeeded and so stores those credentials for the rest of the session!With this in mind, I sought clarification:
The RFC 2617 (http://www.faqs.org/rfcs/rfc2617.html#ixzz0eboUfnrl) does not mention anywhere the use of the
403 Forbidden
status code. In fact, what it actually has to say on the matter is the following:WCF does neither of these. It neither correctly sends an
401 Unauthorized
status code. Nor does it include aWWW-Authenticate
header.Now to find the smoking gun within the WCF source code:
I discovered that in the
HttpRequestContext
class is a method calledProcessAuthentication
, which contains the following (excerpt):I defend Microsoft on a lot of things but this is indefensible.
Fortunately, I have got it working to an "acceptable" level. It just means that if the user accidently enters their username/password incorrectly then the only way to get another attempt is to fully close their web browser and restart it to retry. All because WCF is not responding to the failed authentication attempt with a
401 Unauthorized
and aWWW-Authenticate
header as per the specification.我找到了基于此的解决方案 链接和这个。
第一个是重写名为 CustomUserNameValidator 的类中的 Validate 方法,该类继承自 System.IdentityModel.Selectors.UserNamePasswordValidator:
技巧是更改异常“HttpStatusCode”的属性到 HttpStatusCode.Unauthorized
第二个是在 App.config 中创建 serviceBehavior ,如下所示:
最后,我们必须指定 webHttpBinding 的配置并将其应用到端点:
I've found the solution based in this link and this.
The first is to override the method Validate in a class called CustomUserNameValidator wich inherits from System.IdentityModel.Selectors.UserNamePasswordValidator:
The trick was change the attribute of the exception "HttpStatusCode" to HttpStatusCode.Unauthorized
The second is create the serviceBehavior in the App.config as follows:
Finally we must to specify the configuration for the webHttpBinding and apply it to the endpoint:
是的,您可以为基于 REST 的 WCF 服务提供基本身份验证。但是,您必须遵循几个步骤才能获得完整且安全的解决方案,到目前为止,大多数响应都是所需所有部分的片段。
将您的自托管服务配置为将 SSL 证书绑定到您托管 WCF 服务的端口。这与通过 IIS 等使用托管主机时应用 SSL 证书有很大不同。您必须使用命令行实用程序应用 SSL 证书。您不希望在不使用 SSL 的情况下在 REST 服务上使用基本身份验证,因为标头中的凭据不安全。以下是我写的 (2) 篇详细帖子,详细说明了如何执行此操作。您的问题太大,无法在论坛帖子中提供所有详细信息,因此我提供包含全面详细信息和分步说明的链接:
应用和使用使用自托管 WCF 服务的 SSL 证书
创建 WCF RESTful使用基于 SSL 的 HTTPS 提供服务并保护其安全
将您的服务配置为使用基本身份验证。这也是一个多部分解决方案。第一个是将您的服务配置为使用基本身份验证。第二个是创建“customUserNamePasswordValidatorType”并检查凭据以对客户端进行身份验证。我看到上一篇文章回避了这一点,但是它没有使用 HTTPS,并且只是解决方案的一小部分;请注意那些未提供包含配置和安全性的端到端解决方案的指南。最后一步是查看安全上下文,以便在需要时在方法级别提供授权。我写的下面的文章将逐步指导您如何配置、验证和授权您的客户端。
RESTful 服务:使用基本身份验证对客户端进行身份验证
这是将基本身份验证与自托管 WCF 服务结合使用所需的端到端解决方案。
Yes you can provide Basic authentication for REST based WCF services. However there are several steps which you must follow to have a complete and secure solution and thus far most responses are fragments of all the pieces needed.
Configure your self-hosted service to have a SSL certificate bound to the port which you are hosting your WCF service on. This is very different than applying a SSL cert when using managed hosting through something like IIS. You have to apply the SSL certificate using a command line utility. You DO NOT want to use Basic Authentication on a REST service without using SSL because the credentials in the header on not secure. Here are (2) detailed posts that I wrote on exactly how to do this. Your question is too big to have all the details on a forum post, so that is why I am providing the links with comprehensive details and step by step instructions:
Applying and Using a SSL Certificate With A Self-Hosted WCF Service
Creating a WCF RESTful Service And Secure It Using HTTPS Over SSL
Configure your service to use Basic authentication. This is a multi-part solution as well. 1st is configuring your service to use Basic authentication. The second is to create a 'customUserNamePasswordValidatorType' and inspect the credentials to authenticate the client. I see the last post eluded to this, however it did not use HTTPS and is only 1 very small part of the solution; be careful of guidance that does not provided an end-to-end solution inclusive of configuration and security. The last step is to look at the security context to provide authorization at the method level if needed. The following post I wrote takes you step-by-step on how to configure, authenticate, and authorize your clients.
RESTful Services: Authenticating Clients Using Basic Authentication
This is the end-to-end solution needed for using Basic Authentication with self-hosted WCF services.