.net 使用 RESTful WCF 和 Windows 窗体的用户/通行证身份验证

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/395892/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-03 10:53:28  来源:igfitidea点击:

User/Pass Authentication using RESTful WCF & Windows Forms

.netwcfrestful-authenticationws-security

提问by GONeale

What is the best approach to implementing authorisation/authentication for a Windows Forms app talking to an IIS-hosted RESTful WCF Service?

为与 IIS 托管的 RESTful WCF 服务通信的 Windows 窗体应用程序实现授权/身份验证的最佳方法是什么?

The reason I ask is I am very confused, after sifting through different articles and posts expressing a different method and eventually hitting a ~650 page document on WCF Security Best Practices" (http://www.codeplex.com/WCFSecurityGuide) I am just uncertain which approach is the BEST to take and how to get started on implementation, given my scenario.

我问的原因是我很困惑,在筛选了表达不同方法的不同文章和帖子并最终找到了关于 WCF 安全最佳实践的约 650 页文档“(http://www.codeplex.com/WCFSecurityGuide)我是只是不确定哪种方法是最好的,以及如何开始实施,考虑到我的情况。

I started with this article "A Guide to Designing and Building RESTful Web Services with WCF 3.5" (http://msdn.microsoft.com/en-us/library/dd203052.aspx) and a PDC video on RESTful WCF services, which was great and helped me implement my first REST-friendly WCF service,

我从这篇文章“使用 WCF 3.5 设计和构建 RESTful Web 服务的指南”(http://msdn.microsoft.com/en-us/library/dd203052.aspx)和一个关于 RESTful WCF 服务的 PDC 视频开始很棒,帮助我实现了我的第一个 REST 友好的 WCF 服务,

After I had the service working, I returned to implement security, see. "Security Considerations" (quarter down the page) and attempted to implement a HTTP Authorization header as per the instructions, however I found the code to be incomplete (see how 'UserKeys' variable was never declared). This is the point at which I tried to research more on how to do this (using a HMAC hash with the "Authorization" HTTP header, but could not find much on google?) it led me to other articles regarding message-level security, forms auth and custom validators and frankly I am not sure which is the best and most appropriate approach to take now.

在我让服务工作后,我返回来实现安全,见。“安全注意事项”(页面下方的四分之一)并尝试按照说明实现 HTTP 授权标头,但是我发现代码不完整(请参阅从未声明“UserKeys”变量的方式)。这是我试图更多地研究如何做到这一点(使用带有“授权”HTTP 标头的 HMAC 哈希,但在谷歌上找不到太多内容?)表单身份验证和自定义验证器,坦率地说,我不确定现在采用哪种方法是最好和最合适的。

So with all that said (and thanks for listening up till now!), I guess my main questions are,

综上所述(感谢您到现在为止的聆听!),我想我的主要问题是,

- Which security implementation should I use?

- Is there any way to avoid sending the username/password with every WCF call? I would prefer not to send these extra bytes if a connection has been established at the beginning, which it will be before subsequent calls are allowed to be made after login.

- Should I even really be concerned about anything other than plain text if I am using SSL?

- 我应该使用哪种安全实现?

- 有什么办法可以避免在每次 WCF 调用时发送用户名/密码?如果在开始时建立了连接,我不想发送这些额外的字节,这将是在登录后允许进行后续调用之前。

- 如果我使用 SSL,我是否真的应该关心纯文本以外的任何内容?

As said, .NET 3.5 win forms app, IIS-hosted WCF service, however what is important is I wish any and all WCF services to require this authorization procedure (however it should be, session, http header or otherwise) as I do not want anybody to be able to hit these services from the web.

如上所述,.NET 3.5 赢得表单应用程序、IIS 托管的 WCF 服务,但重要的是我希望任何和所有 WCF 服务都需要此授权程序(但它应该是会话、http 标头或其他),因为我没有希望任何人都能够从网络访问这些服务。

I know the above post is large but I had to express the route I have already been down and what I need to accomplish, any and all help is greatly appreciated.

我知道上面的帖子很大,但我必须表达我已经下来的路线以及我需要完成的工作,非常感谢任何和所有帮助。

PS: I am also aware of this post How to configure secure RESTful services with WCF using username/password + SSLand if the community suggests I move away from REST for WCF services, I can do this, however I started with this to keep consistency for any public APIs to come.

PS:我也知道这篇文章如何使用用户名/密码 + SSL 使用 WCF 配置安全的 RESTful 服务,如果社区建议我放弃 WCF 服务的 REST,我可以这样做,但是我从这个开始以保持一致性任何公共 API 的到来。

I think it's important I state how I am accessing my WCF Service (contacting the service is working, but what is the best way to validate credentials - and then return the Member object?):

我认为重要的是我声明我如何访问我的 WCF 服务(联系服务正在工作,但验证凭据的最佳方法是什么 - 然后返回 Member 对象?):

WebChannelFactory<IMemberService> cf = new WebChannelFactory<IMemberService>(
                new Uri(Properties.Settings.Default.MemberServiceEndpoint));
            IMemberService channel = cf.CreateChannel();
            Member m = channel.GetMember("user", "pass");

Code that was half implemented from MS article (and some of my own for testing):

从 MS 文章中实现了一半的代码(以及我自己的一些用于测试的代码):

 public Member GetMember(string username, string password)
    {
        if (string.IsNullOrEmpty(username))
            throw new WebProtocolException(HttpStatusCode.BadRequest, "Username must be provided.", null);
        if (string.IsNullOrEmpty(password))
            throw new WebProtocolException(HttpStatusCode.BadRequest, "Password must be provided.", null);

        if (!AuthenticateMember(username))
        {
            WebOperationContext.Current.OutgoingResponse.StatusCode = HttpStatusCode.Unauthorized;
            return null;
        }

        return new Member() { Username = "goneale" };
    }

采纳答案by Nicholas Piasecki

Well, I don't have any experience with the REST capabilities of WCF, but I did wrestle a lot with understanding the implications of security choices in my WCF security question. As you've noticed, there's a real lack of documentation on WCF out their on the Web, and my REST experience is limited, so take my answers with a grain of salt:

好吧,我对 WCF 的 REST 功能没有任何经验,但我确实在理解我的 WCF 安全问题中安全选择的影响方面做了很多努力。正如您所注意到的,Web 上确实缺乏有关 WCF 的文档,而且我的 REST 经验有限,因此请谨慎回答我的回答:

Which security implementation should I use?

我应该使用哪种安全实现?

and

Should I even really be concerned about anything other than plain text if I am using SSL?

如果我使用 SSL,我是否真的应该关心纯文本以外的任何内容?

Basic authentication over SSL is fine--after all, this how a great deal of existing Web sites authenticate users. (When you log into your Amazon shopping account, they're just transmitting your username and password as you typed it over an SSL connection.) I understand what the article is saying about security and dictionary attacks, but blah blah blah, keep it simple and get something working first. UPS's Plain Old XML API asks for the username and password with each call, so does FedEx's POX API, so does PayPal's SOAP API and CyberSource's SOAP API--this seems to be fine enough for real world usage.

基于 SSL 的基本身份验证很好——毕竟,这是大量现有网站对用户进行身份验证的方式。(当您登录到您的亚马逊购物帐户时,他们只是在您通过 SSL 连接输入时传输您的用户名和密码。)我理解文章中关于安全性和字典攻击的内容,但等等等等,保持简单并先做一些工作。UPS 的Plain Old XML API 在每次调用时都要求输入用户名和密码,FedEx 的POX API 也是如此,PayPal 的SOAP API 和Cyber​​Source 的SOAP API 也是如此——这对于现实世界的使用来说似乎已经足够了。

Is there any way to avoid sending the username/password with every WCF call? I would prefer not to send these extra bytes if a connection has been established at the beginning, which it will be before subsequent calls are allowed to be made after login.

有什么办法可以避免在每次 WCF 调用时发送用户名/密码?如果在开始时建立了连接,我不想发送这些额外的字节,这将是在登录后允许进行后续调用之前。

This is one that I can answer a little bit more confidently. Usually, we try to design our public-facing WCF services to be stateless. That way, our WCF services scale easily; just throw more hardware and more servers and load balancers at the problem, and we don't have to worry about sticky sessions or maintaining session state somewhere. So that means that if we want to "keep a user logged in," then it's not something that's going to happen on the server.

这是一个我可以更自信地回答的问题。通常,我们尝试将面向公众的 WCF 服务设计为无状态的。这样,我们的 WCF 服务就可以轻松扩展;只需在问题上投入更多的硬件和更多的服务器和负载平衡器,我们就不必担心粘性会话或在某处维护会话状态。所以这意味着如果我们想要“保持用户登录”,那么它不会发生在服务器上。

What I ended up doing is treating my Web site as a trusted subsystem. It authenticated against the WCF service using a pre-shared X509 certificate, and if a customer was logged into the Web site via Forms Authentication, then it would send a customer username header to the service; a custom endpoint behavior on the WCF service would look for this header, see that it was installed by a trusted subsystem, and proceed to impersonate that user without the user's password needing to be supplied or verified against the database.

我最终做的是将我的网站视为受信任的子系统。它使用预先共享的 X509 证书对 WCF 服务进行身份验证,如果客户通过表单身份验证登录到网站,那么它将向服务发送一个客户用户名标头;WCF 服务上的自定义端点行为将查找此标头,查看它是否由受信任的子系统安装,然后继续模拟该用户,而无需提供用户密码或针对数据库进行验证。

Since you're using REST, you could probably use a cookie on the client side to maintain state. If you use ASP.NET Compatibility mode, I think you can even use Forms Authentication directly, but I don't know much about this approach since my WCF service was not IIS hosted.

由于您使用的是 REST,您可能可以在客户端使用 cookie 来维护状态。如果你使用ASP.NET兼容模式,我想你甚至可以直接使用Forms Authentication,但是我对这种方法了解不多,因为我的WCF服务不是IIS托管的。

In short, though, you're going to have to send somethingwith each request to identify the user, whether that is the username and password, just the username, or some hashed value stored in the cookie. If the last option, I guess you'd have to have some sort of Login()method or something on the service, something that would send an "okay, you're logged if you pass in this hash value with future requests." But not all REST clients will be expecting to receive cookies, just simple GET/PUT/POST/DELETE requests without any state.

简而言之,您将不得不在每个请求中发送一些信息来识别用户,无论是用户名和密码、用户名还是存储在 cookie 中的一些散列值。如果是最后一个选项,我想您必须Login()在服务上使用某种方法或某些东西,这些东西会发送“好吧,如果您在将来的请求中传递此哈希值,您就会被记录”。但并非所有 REST 客户端都希望接收 cookie,只是没有任何状态的简单 GET/PUT/POST/DELETE 请求。

If those were my shoes, I'd either go for the trusted subsystem approach (where a username header is supplied along with pre-shared credentials for the subsystem) or I'd require authentication on every call. The service would probably get some high-performance authentication caching mechanism if all those repeated requests became a problem.

如果那是我的鞋子,我要么选择受信任的子系统方法(其中提供用户名标头以及子系统的预共享凭据),要么我要求每次调用都进行身份验证。如果所有这些重复请求都成为问题,该服务可能会获得一些高性能的身份验证缓存机制。

Hope that helps a little bit.

希望能有所帮助。

回答by Tawani

Using Basic authentication:

使用基本身份验证:

WebHttpBinding binding = new WebHttpBinding();
binding.SendTimeout = TimeSpan.FromSeconds(25);
binding.Security.Mode = WebHttpSecurityMode.TransportCredentialOnly;
binding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;

Uri address = new Uri("http://localhost:3525/WcfRestWeb/Quotes.svc");

WebChannelFactory<IQuoteService> factory =
             new WebChannelFactory<IQuoteService>(binding, address);

factory.Credentials.UserName.UserName = "tan";
factory.Credentials.UserName.Password = "wani";

IQuoteService proxy = factory.CreateChannel();

var response = proxy.GenerateQuote(GetQuoteRequest());
Console.WriteLine("Quote Amount: " + response.QuoteAmount);

回答by GONeale

Thanks for the answers. Stepping back and looking clearly and unbiased at the problem as a whole (in other words ignoring the 4+ hours I invested looking into RESTful services) I am attempting to get the thing working without REST for now and the references I am attempting to follow at the moment are these: -

感谢您的回答。退后一步,从整体上清晰而公正地看待问题(换句话说,忽略了我在研究 RESTful 服务方面投入的 4 个多小时)我现在正试图在没有 REST 的情况下使事情正常工作,以及我试图遵循的参考资料现在是这些:-

This seems applicable for what I want.

这似乎适用于我想要的。

lextm:I hear you on this, after I wrote the post I scanned closer through the WCF security guide and made notes on all my requirements based on the options given they want you to think about on each tenet.

lextm:我听到了你的声音,在我写完这篇文章后,我仔细浏览了 WCF 安全指南,并根据他们希望你在每个原则上考虑的选项记录了我的所有要求。

I have chosen:
- Transfer Security Mode: Transport Security
- Auth. Option: Basic Security
- Binding: wsHttpBinding
- Custom authentication with username validator

我选择了:
- 传输安全模式:传输安全
- 身份验证。选项:基本安全
- 绑定:wsHttpBinding
- 使用用户名验证器的自定义身份验证

In light of the examples provided for each and looking at the use case of windows forms w/ WCF service it seems like the best way to go.

根据为每个提供的示例并查看带有 WCF 服务的 Windows 窗体的用例,这似乎是最好的方法。

Nicholas:Agreed, designing the services to be stateless is probably a better approach.

Nicholas:同意,将服务设计为无状态可能是更好的方法。

So based on the article I will be following when I get time, it utilises the X509 cert. which I am very new to (understand you are using this Nicholas) will this be fine given this client app can be downloaded from the internet and installed on anybody's PC who has an account with my website?

因此,根据我有空时将关注的文章,它使用了 X509 证书。我对它很陌生(理解你正在使用这个 Nicholas)鉴于这个客户端应用程序可以从互联网上下载并安装在任何拥有我网站帐户的 PC 上,这会好吗?

Cheers for all your help, Graham

为你的帮助干杯,格雷厄姆

PS: I think this is the closest use case to my scenario(except I wish to use transport security), should I be considering implementing this as it does not bother with a cert? From the quote I read I might need the cert. as "The X509 certificate encryption is required by WCF because the client credentials (username/password) are passed as clear text in the SOAP message." - however from what I've learnt and what we said, if I am using SSL, this point is probably moot?

PS:我认为这是最接近我的场景的用例(除非我希望使用传输安全),我是否应该考虑实现它,因为它不需要证书?从我读到的报价中,我可能需要证书。作为“WCF 需要 X509 证书加密,因为客户端凭据(用户名/密码)在 SOAP 消息中以明文形式传递。” - 然而,根据我所学到的和我们所说的,如果我使用 SSL,这一点可能没有实际意义?

回答by Lex Li