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

时间:2008-09-11 09:18:50

标签: .net wcf web-services

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

我现在想要使用完全相同的Web服务编写Windows应用程序。为了处理身份验证,我启用了Authentication service,并且可以调用“login”来验证我的用户... Okey,一切都很好......但是我怎样才能在我的其他服务客户端上设置身份验证cookie? !

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

  • MyDataService.svc< - 处理我数据的那个
  • AuthenticationService.svc< - Windows应用程序必须调用以进行身份​​验证的那个。

我不想为Windows客户端创建新服务,或使用其他绑定...

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

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

6 个答案:

答案 0 :(得分:5)

我终于找到了一种方法来完成这项工作。对于身份验证,我使用的是“WCF Authentication Service”。验证服务时将尝试设置身份验证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();
}      

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

我对这段代码完全不满意,我认为更好的选择可能是使用“Web Reference”而不是“Service Reference”,而是使用.NET 2.0堆栈。

答案 1 :(得分:2)

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

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

实际上,当使用成员资格提供程序验证对服务的每次调用时,我发现WCF运行良好。因此,在给出的示例中,您希望将成员资格提供程序身份验证gubbins添加到MyDataService的服务配置中,而根本没有单独的身份验证服务。

有关详细信息,请参阅MSDN文章here

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

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

给出的一件事是能够提供“登录”功能。为此,您可以提供一个(经过身份验证的!)服务合同,该服务合同不执行任何操作(除非在身份验证失败时引发错误),或者您可以使用原始引用文章中描述的成员资格提供程序服务。

答案 2 :(得分:1)

在客户端上修改您的< binding>服务的标记(在< system.serviceModel>内)包含:allowCookies =“true”

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

答案 3 :(得分:0)

可以隐藏自定义消息检查器后面的大部分额外代码。行为,所以你不需要自己修改OperationContextScope。

我稍后会尝试嘲笑并发送给你。

- larsw

答案 4 :(得分:0)

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

Here is a brief article关于如何使用它。可能会有更好的,但这应该让你开始。

我们为当前的WCF服务和Silverlight 2应用程序提供了无状态路由。可以使用Silverlight 2来处理与TransportWithMessageCredential安全绑定的服务,尽管它在Silverlight端需要一些自定义安全代码。结果是任何应用程序都可以通过在邮件头中设置用户名和密码来访问服务。这可以在自定义IRequestChannel实现中完成一次,这样开发人员就不必担心自己设置值。虽然WCF确实有一个简单的方法让开发人员这样做,我相信是serviceProxy.Security.Username和serviceProxy.Security.Password或同样简单的东西。

答案 5 :(得分:0)

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