3

抱歉标题太长了。

这是关于 WCF 配置和安全性的。我有以下情况:

  • 一台服务器 (IIS)
  • N 个客户端(WPF 应用程序)
  • 用于在客户端和服务器之间进行通信的 Web 服务
  • 一切都在同一个局域网和同一个域中
  • 我需要一些双工通信,以便服务器可以通知所有客户端(无轮询,但使用 WCF 回调)
  • 用户凭据(登录名/密码)由活动目录管理
  • 用户身份验证是“每个用户”,而不是“每个 Windows 帐户”或“每个机器”

理想情况下,我希望有 2 种不同的服务:

一个需要 WCF 会话,以便我可以使用回调:

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IService1Callback))]
public interface IService1
{
    [OperationContract(IsOneWay = false, IsInitiating = true)]
    void Subscribe();

    [OperationContract(IsOneWay = false, IsTerminating = true)]
    void Unsubscribe();
}

一个没有,所以我可以使用旧的方式来编写无状态、高效和可维护的服务:每个 WCF 调用都经过身份验证、授权,并在服务器端生成一个新的 Service 实现实例:

[ServiceContract]
public interface IService2
{
    [OperationContract]
    int DoSomeStuff();
}

问题是,我们希望每个客户端都针对活动目录进行身份验证。因此,在客户端应用程序启动时,每个客户端都必须指定登录名、密码和域。问题是 AD 身份验证非常耗时:

using(PrincipalContext pc = new PrincipalContext(ContextType.Domain, "theDomain"))
{
    if (!pc.ValidateCredentials("theUser", "thePassword"))
    {
        throw new SecurityException();
    }
}

我的第一个想法是使用该IService1服务(负责发送回调)作为身份验证服务:

[ServiceContract(SessionMode = SessionMode.Required, CallbackContract = typeof(IService1Callback))]
public interface IService1
{
    [OperationContract(IsOneWay = false, IsInitiating = true)]
    void Login(string login, string password, string domain);

    [OperationContract(IsOneWay = false, IsTerminating = true)]
    void Logout();
}

所以在Login操作实现中,我们可以只检查一次用户登录/密码对 AD 的检查,并依赖 WCF 会话来处理来自客户端的下一个 WCF 请求。问题是,我不想IService1因为会话模式而对服务发出其他请求RequiredInstanceContextMode也就是说PerSession(是的,除了登录/注销/客户端通知之外,我想避免其他操作的丑陋的客户端代理单例模式) .

所以问题是:我如何构建和配置我的服务,所以:

  • 我不需要针对每个 WCF 请求向 AD 提出请求
  • 我有一些服务器回调
  • IService2对于回调服务(不是“实际”服务),我每个会话只有单例模式/会话所需/实例上下文

我在想wsHttpBindingforIService2netTcpBindingfor IService1。关于传输安全性(传输或消息)的选择和凭证类型(Windows、用户名、..?)的选择,我不确定。

任何帮助将不胜感激。

4

2 回答 2

0

你可以试试这个:

创建一个自定义消息检查器,它采用两个参数 - 用户名和密码,当客户端第一次访问您的主机时,您在 AD 服务器上进行身份验证。但在将响应返回给客户端之前,添加一个限时 cookie。当客户端再次请求时,检查请求的 OperationContext 中是否存在 cookie 并跳过 AD 认证。

关于此解决方案,有两件事需要了解。首先,当您使用消息检查器时,每个请求(不仅仅是登录)都会点击过程。他们就是这样工作的。但是由于 cookie 检查,只要 cookie 有效,您就可以跳过后续的 AD 检查。它消除了登录过程的必要性。

像这样的东西:

public class SchemaLoggingMessageInspector : Dispatcher.IDispatchMessageInspector
{

public object AfterReceiveRequest(ref System.ServiceModel.Channels.Message request,
                        System.ServiceModel.IClientChannel channel, 
                        System.ServiceModel.InstanceContext instanceContext)    {

    var cookieHeader = WebOperationContext.Current.IncomingRequest.Headers[System.Net.HttpRequestHeader.Cookie];
    if (!String.IsNullOrEmpty(cookieHeader)){
        var match = cookieHeader.Split(';').Select(cookie => cookie.Split('=')).FirstOrDefault(kvp => kvp[0] == "BigCookie");
        if (match != null)
        {
            return True
        }
    }

    if (WcfBaseFunctionality.eSecurityType == SecurityEnum.authentication) {
        string username = AuthenticationBehavior.GetHeaderData("Username");
        string password = AuthenticationBehavior.GetHeaderData("Password");

        if (ValidateAuthentication(username, password){
            WebOperationContext.Current.OutgoingResponse.Headers[System.Net.HttpResponseHeader.SetCookie] = Cookie="BigCookie"; 
            return True;
        }else{
            return False;
        };
    }

    return False;
}

    private bool ValidateAuthentication(string UserName, string PWD)
    {
        //add code to check ID/password against AD server
        return true;
    }
}

就客户端回调而言,我从未尝试过。对不起。祝你的网络服务好运。

于 2013-06-13T14:26:24.860 回答
0

如果我理解正确:

  • 您需要服务 (1)
    • 负责身份验证,令牌,任何和
    • 还为每个会话提供回调
  • 你需要一个实际的工人服务
    • 可以做加工
    • 可以发起回调
    • 只有经过身份验证才能工作

据我所知,身份验证与会话问题相关联,这不是难题(如果您同时需要联合(基于令牌的身份)和 AD,将使用 ADFS)。我用这个设置尝试了两个简单的服务

  • service1 : wsHttpBinding (为了会话)
  • service2 : basicHttpBinding (为简单起见,也可以是 net tcp)

重要的一点是确保第二个的实例不连接到第一个(基于会话)。

考虑到处理的结束(服务 2 的责任)应该触发回调(服务 1 的责任),因此无法避免共享某种回调信息(这也意味着共享会话 ID 或任何标识服务 1 活动会话实例的内容) .

我尝试了最简单的方法,即使用缓存来存储针对会话密钥的回调实例。(我知道很多反例说明为什么这是邪恶的,但它仅适用于 poc)。这样两个服务的生命周期就解耦了,仍然可以调用回调。

我确信生成正确的令牌并将令牌检查绑定到处理服务是有据可查的(ADFS 及其消费者)。

我仍然认为关键是在那里使用共享回调。

如果我完全误解了您的问题,请告诉我。

谢谢,尼古拉

于 2013-06-17T18:41:06.650 回答