WCF、ASP.NET 成员资格提供程序和身份验证服务

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/56112/
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 09:47:37  来源:igfitidea点击:

WCF, ASP.NET Membership Provider and Authentication Service

.netwcfweb-services

提问by Jonas Folles?

I have written a Silverlight 2 application communicating with a WCF service (BasicHttpBinding). The site hosting the Silverlight content is protected using a ASP.NET Membership Provider. I can access the current user using HttpContext.Current.User.Identity.Name from my WCF service, and I have turned on AspNetCompatibilityRequirementsMode.

我编写了一个与 WCF 服务 (BasicHttpBinding) 通信的 Silverlight 2 应用程序。托管 Silverlight 内容的站点使用 ASP.NET 成员资格提供程序进行保护。我可以使用 HttpContext.Current.User.Identity.Name 从我的 WCF 服务访问当前用户,并且我已经打开了 AspNetCompatibilityRequirementsMode。

I now want to write a Windows application using the exact same web service. To handle authentication I have enabled the Authentication service, and can call "login" to authenticate my user... Okey, all good... But how the heck do I get that authentication cookie set on my other service client?!

我现在想使用完全相同的 Web 服务编写一个 Windows 应用程序。为了处理身份验证,我启用了身份验证服务,并且可以调用“登录”来对我的用户进行身份验证......好吧,一切都很好......但是我该如何在我的其他服务客户端上设置身份验证 cookie?!

Both services are hosted on the same domain

两个服务都托管在同一个域中

  • MyDataService.svc <- the one dealing with my data
  • AuthenticationService.svc <- the one the windows app has to call to authenticate.
  • MyDataService.svc <- 处理我的数据的那个
  • AuthenticationService.svc <- Windows 应用程序必须调用以进行身份​​验证的那个。

I don't want to create a new service for the windows client, or use another binding...

我不想为 windows 客户端创建一个新服务,或者使用另一个绑定...

The Client Application Services is another alternative, but all the examples is limited to show how to get the user, roles and his profile... But once we're authenticated using the Client Application Services there should be a way to get that authentication cookie attached to my service clients when calling back to the same server.

客户端应用程序服务是另一种选择,但所有示例都仅限于展示如何获取用户、角色和他的个人资料……但是一旦我们使用客户端应用程序服务进行了身份验证,就应该有一种方法可以获取该身份验证 cookie回调到同一台服务器时附加到我的服务客户端。

According to input from colleagues the solution is adding a wsHttpBinding end-point, but I'm hoping I can get around that...

根据同事的意见,解决方案是添加一个 wsHttpBinding 端点,但我希望我能解决这个问题......

采纳答案by Jonas Folles?

I finally found a way to make this work. For authentication I'm using the "WCF Authentication Service". When authenticating the service will try to set an authentication cookie. I need to get this cookie out of the response, and add it to any other request made to other web services on the same machine. The code to do that looks like this:

我终于找到了一种方法来完成这项工作。对于身份验证,我正在使用“ WCF 身份验证服务”。验证服务时,将尝试设置验证 cookie。我需要从响应中获取此 cookie,并将其添加到对同一台机器上的其他 Web 服务发出的任何其他请求中。执行此操作的代码如下所示:

var authService = new AuthService.AuthenticationServiceClient();
var diveService = new DiveLogService.DiveLogServiceClient();

string cookieHeader = "";
using (OperationContextScope scope = new OperationContextScope(authService.InnerChannel))
{
    HttpRequestMessageProperty requestProperty = new HttpRequestMessageProperty();
    OperationContext.Current.OutgoingMessageProperties[HttpRequestMessageProperty.Name] = requestProperty;
    bool isGood = authService.Login("jonas", "jonas", string.Empty, true);
    MessageProperties properties = OperationContext.Current.IncomingMessageProperties;
    HttpResponseMessageProperty responseProperty = (HttpResponseMessageProperty)properties[HttpResponseMessageProperty.Name];
    cookieHeader = responseProperty.Headers[HttpResponseHeader.SetCookie];                
}

using (OperationContextScope scope = new OperationContextScope(diveService.InnerChannel))
{
    HttpRequestMessageProperty httpRequest = new HttpRequestMessageProperty();
    OperationContext.Current.OutgoingMessageProperties.Add(HttpRequestMessageProperty.Name, httpRequest);
    httpRequest.Headers.Add(HttpRequestHeader.Cookie, cookieHeader);
    var res = diveService.GetDives();
}      

As you can see I have two service clients, one fo the authentication service, and one for the service I'm actually going to use. The first block will call the Login method, and grab the authentication cookie out of the response. The second block will add the header to the request before calling the "GetDives" service method.

如您所见,我有两个服务客户端,一个用于身份验证服务,另一个用于我实际要使用的服务。第一个块将调用 Login 方法,并从响应中获取身份验证 cookie。第二个块将在调用“GetDives”服务方法之前将标头添加到请求中。

I'm not happy with this code at all, and I think a better alternative might be to use "Web Reference" in stead of "Service Reference" and use the .NET 2.0 stack instead.

我对这段代码一点都不满意,我认为更好的替代方法可能是使用“Web 引用”而不是“服务引用”并使用 .NET 2.0 堆栈。

回答by Jeremy McGee

Web services, such as those created by WCF, are often best used in a "stateless" way, so each call to a Web service starts afresh. This simplifies the server code, as there's no need to have a "session" that recalls the state of the client. It also simplifies the client code as there's no need to hold tickets, cookies, or other geegaws that assume something about the state of the server.

Web 服务(例如由 WCF 创建的服务)通常最好以“无状态”方式使用,因此对 Web 服务的每次调用都会重新开始。这简化了服务器代码,因为不需要有一个调用客户端状态的“会话”。它还简化了客户端代码,因为不需要持有票证、cookie 或其他假设服务器状态的东西。

Creating two services in the way that is described introduces statefulness. The client is either "authenticated" or "not authenticated", and the MyDataService.svc has to figure out which.

以所描述的方式创建两个服务会引入状态性。客户端要么“经过身份验证”,要么“未经过身份验证”,MyDataService.svc 必须确定哪个。

As it happens, I've found WCF to work well when the membership provider is used to authenticate everycall to a service. So, in the example given, you'd want to add the membership provider authentication gubbins to the service configuration for MyDataService, and not have a separate authentication service at all.

碰巧的是,我发现当成员资格提供程序用于验证对服务的每个调用时,WCF 工作得很好。因此,在给出的示例中,您希望将成员资格提供程序身份验证 gubbins 添加到 MyDataService 的服务配置中,并且根本没有单独的身份验证服务。

For details, see the MSDN article here.

有关详细信息,请参阅此处的 MSDN 文章。

[What's very attractive about this to me, as I'm lazy, is that this is entirely declarative. I simply scatter the right configuration entries for my MembershipProvider in the app.config for the application and! bingo! all calls to every contract in the service are authenticated.]

[这对我来说非常有吸引力,因为我很懒,这完全是声明性的。我只是在应用程序的 app.config 中为我的 MembershipProvider 散布正确的配置条目!答对了!对服务中每个合约的所有调用都经过身份验证。]

It's fair to note that this is not going to be particularly quick. If you're using SQL Server for your authentication database you'll have at least one, perhaps two stored procedure calls per service call. In many cases (especially for HTTP bindings) the overhead of the service call itself will be greater; if not, consider rolling your own implementation of a membership provider that caches authentication requests.

公平地说,这不会特别快。如果您将 SQL Server 用于身份验证数据库,则每个服务调用将至少有一个,也许两个存储过程调用。在很多情况下(特别是对于 HTTP 绑定),服务调用本身的开销会更大;如果没有,请考虑滚动您自己的缓存身份验证请求的成员资格提供程序的实现。

One thing that this doesn'tgive is the ability to provide a "login" capability. For that, you can either provide an (authenticated!) service contract that does nothing (other than raise a fault if the authentication fails), or you can use the membership provider service as described in the original referenced article.

没有提供的一件事是提供“登录”功能的能力。为此,您可以提供一个(经过身份验证的!)服务合同,它什么都不做(除了在身份验证失败时引发故障),或者您可以使用原始引用文章中所述的成员资格提供者服务。

回答by Jeremy McGee

On the client modify your <binding> tag for the service (inside <system.serviceModel>) to include: allowCookies="true"

在客户端修改您的服务的 <binding> 标记(在 <system.serviceModel> 内)以包括:allowCookies="true"

The app should now persist the cookie and use it. You'll note that IsLoggedIn now returns true after you log in -- it returns false if you're not allowing cookies.

应用程序现在应该保留 cookie 并使用它。您会注意到 IsLoggedIn 现在在您登录后返回 true - 如果您不允许使用 cookie,它将返回 false。

回答by larsw

It is possible to hide much of the extra code behind a custom message inspector & behavior so you don't need to take care of tinkering with the OperationContextScope yourself.

可以将大部分额外代码隐藏在自定义消息检查器和行为背后,因此您无需自行修改 OperationContextScope。

I'll try to mock something later and send it to you.

稍后我会尝试模拟一些内容并将其发送给您。

--larsw

--larsw

回答by Chuck

You should take a look at the CookieContainerobject in System.Net. This object allows a non-browser client to hang on to cookies. This is what my team used the last time we ran into that problem.

您应该查看System.Net中的CookieContainer对象。此对象允许非浏览器客户端挂起 cookie。这是我的团队上次遇到该问题时使用的方法。

Here is a brief articleon how to go about using it. There may be better ones out there, but this should get you started.

这是一篇关于如何使用它的简短文章。那里可能有更好的,但这应该让你开始。

We went the stateless route for our current set of WCF services and Silverlight 2 application. It is possible to get Silverlight 2 to work with services bound with TransportWithMessageCredential security, though it takes some custom security code on the Silverlight side. The upshot is that any application can access the services simply by setting the Username and Password in the message headers. This can be done once in a custom IRequestChannel implementation so that developers never need to worry about setting the values themselves. Though WCF does have an easy way for developers to do this which I believe is serviceProxy.Security.Username and serviceProxy.Security.Password or something equally simple.

我们为当前的 WCF 服务集和 Silverlight 2 应用程序采用了无状态路线。可以让 Silverlight 2 与与 TransportWithMessageCredential 安全性绑定的服务一起使用,尽管它在 Silverlight 端需要一些自定义安全代码。结果是任何应用程序都可以通过在消息标题中设​​置用户名和密码来访问服务。这可以在自定义 IRequestChannel 实现中完成一次,因此开发人员无需担心自己设置值。尽管 WCF 确实为开发人员提供了一种简单的方法来执行此操作,我认为是 serviceProxy.Security.Username 和 serviceProxy.Security.Password 或同样简单的方法。

回答by Chuck

I wrote this a while back when I was using Client Application Services to authenticate against web services. It uses a message inspector to insert the cookie header. There is a word file with documentation and a demo project. Although its not exactly what you are doing, its pretty close. You can download it from here.

不久前,我在使用客户端应用程序服务对 Web 服务进行身份验证时写了这篇文章。它使用消息检查器来插入 cookie 标头。有一个带有文档和演示项目的 word 文件。虽然它不完全是你在做什么,但它非常接近。你可以从这里下载。