.net - 来自不同客户端的调用之间未清除 WCF AuthorizationContext。 (原为 : When does a WCF service session actually end? )

标签 .net wcf session wcf-sessions

我正在做一些单元测试,并在 WCF 中遇到了一个有趣的问题。我有一项使用 wsHttpBinding 的服务,配置如下:

<bindings>
  <wsHttpBinding>
    <binding name="wsHttpUnsecured">
      <security mode="None">
        <transport clientCredentialType="None" />
        <message clientCredentialType="None" />
      </security>
    </binding>
  </wsHttpBinding>

服务的实现是:
public void DoWork()
{
    OperationContext o = OperationContext.Current;
    if (o == null) return;

    if (o.ServiceSecurityContext.AuthorizationContext.Properties.ContainsKey("x"))
        throw new ApplicationException();

    o.ServiceSecurityContext.AuthorizationContext.Properties.Add("x", "x");
}

它在这里所做的只是检查操作上下文,如果 AuthorizationContext 中没有“X”,则添加一个。如果已经有一个“X”,则异常(exception)。 (这严格设置为一个简单的测试。在正常使用中,这将发生在自定义 AuthorizationManager 和 Token Authenticator 中)。

所以基本上,如果我们在同一个 operationContext 和 AuthorizationContext 中多次调用该方法,那么我们会看到一个异常。

现在,这是我的测试夹具。
    [Test]
    public void CallTwice()
    {
        using (var cli1 = new TestBusinessClient())
        {
            cli1.DoWork();
            cli1.Close();
        }
        using (var cli2 = new TestBusinessClient())
        {
            cli2.DoWork();
            cli2.Close();
        }
    }

因此,遍历运行时发生的事情:
  • 全新 TestBusinessClient被 build 。
  • 它拨打 DoWork() .
  • DoWork()AuthorizationContext.Properties 中找不到“X” .
  • DoWork()将“X”添加到 AuthorizationContext.Properties .
  • 测试方法配置第一个客户端。
  • 新的一秒 TestBusinessClient被 build 。
  • 它拨打 DoWork() .
  • DoWork() 在上次调用的属性中找到“X”。
  • DoWork()抛出异常。

  • 所以我的问题是;为什么是 OperationContextAuthorizationContext当新客户端连接到同一服务时不会被杀死?我明白 wsHttpBinding默认情况下在调用之间使用 session 上下文,但我认为该 session 将是每个客户端。当我连接到客户端的新实例时,我希望 WCF session 以及它的上下文全部更新。

    任何人有任何想法或想法?这里想要的结果是 AuthorizationContext.Properties在两次调用之间重置 DoWork()由两个不同的客户。

    更新 1

    我尝试设置服务 PerCallPerSession ,两者都没有区别。

    我还尝试了打开和关闭可靠消息传递的服务,但都没有改变任何东西。

    我还在第一次调用和第二次调用时保存了我的 operationContext,并比较了两者:
    OperationContext first; // context from first call to DoWork()
    OperationContext second; // context from second call to DoWork() 
    
    (first == second) = false
    (first.ServiceSecurityContext == second.ServiceSecurityContext) = false
    (first.ServiceSecurityContext.AuthorizationContext == second.ServiceSecurityContext.AuthorizationContext) = true
    

    所以看起来操作上下文被更改/重新创建,但某些设置相同 AuthorizationContext在每次后续服务调用中。

    更新 2

    这是所有服务器端的东西:
    [ServiceContract]
    public interface ITestBusiness
    {
        [OperationContract(Action = "*", ReplyAction = "*")]
        string DoWork();
    }
    
    public class TestBusiness : ITestBusiness
    {
        public string DoWork()
        {
            System.ServiceModel.OperationContext o = System.ServiceModel.OperationContext.Current;
            if (o != null)
            {
                if (o.ServiceSecurityContext.AuthorizationContext.Properties.ContainsKey("x"))
                    throw new ApplicationException();
                else
                    o.ServiceSecurityContext.AuthorizationContext.Properties.Add("x", "x");
            }
        }
        return "";
    }
    

    作为健全性检查,我执行了以下操作:
  • 启动 WCF 服务器的实例(使用 Cassini/集成 VS 2008 服务器)。
  • 将测试夹具减少到只有 1 次调用 DoWork() .
  • TestDriven.NET 运行测试在 VS 2008 内。
  • 打开同一个测试.dll来自 NUnit's独立的 GUI 工具,然后运行它。

  • 第一次测试通过,第二次失败。所以看起来这纯粹是服务器端,因为从 2 个不同的进程运行相同的服务调用最终会得到相同的 AuthorizationContext .

    我开始怀疑 WCF 内部的某些东西是否仍然停留在 WindowsAuthentication 上。并重复使用相同的 Auth上下文,因为我使用相同的用户名登录到同一个域?我的服务设置为使用自定义 AuthorizationManager :
            <serviceBehaviors>
                <behavior name="myBehavior">
                    <serviceMetadata httpGetEnabled="false"  />
                    <serviceDebug includeExceptionDetailInFaults="true" />
                    <serviceAuthorization principalPermissionMode="Custom" serviceAuthorizationManagerType="My.Namespace.CustomAuthMgr" />
                </behavior>
    

    哪里My.Namespace.CustomAuthMgr扩展 ServiceAuthorizationManager .如果我在 CustomAuthMgr.CheckAccess() 中设置断点,然后在第一次通话时,operationContext.ServiceSecurityContext.AuthorizationContext很清楚,在第二次通话中,它包含我在上一次通话中放入的任何内容。这是我自己的代码的第一个方法被 WCF 执行,所以在授权阶段之前的东西是重新加载我的 AuthorizationContext .

    更新 3

    一些补充信息:为了验证一些事情,我改变了我的服务实现,不再抛出异常,而是返回一个被调用次数的计数器,加上当前线程 ID:
        public string DoWork()
        {
            var o = System.ServiceModel.OperationContext.Current.ServiceSecurityContext.AuthorizationContext;
            if (o != null)
            {
                if (o.Properties.ContainsKey("x"))
                    o.Properties["x"] = (int)o.Properties["x"] + 1;
                else
                    o.Properties.Add("x", 1);
            }
    
            return o.Properties["x"].ToString() + " | " + System.AppDomain.GetCurrentThreadId().ToString();
        }
    

    然后从 NUnit 运行一次测试GUI 导致:
    1 | 3816
    

    然后我关闭 NUnit GUI,重新启动它,然后再次运行测试:
    2 | 3816
    

    然后我关闭 NUnit再次 GUI,并从 TestDriven.NET 运行测试在 Visual Studio 中:
    3 | 3816
    

    所以它绝对坚持我的AuthorizationContext客户端进程之间,但同一个线程处理每个服务调用,所以可能 AuthorizationContext只是线程静态的还是什么?

    不,这与线程无关。我加了一个 Thread.Sleep(10000);到服务实现,然后运行 ​​2 NUnit GUI 一次,每个 GUI 都打印出“2”但具有不同的线程 ID:
    2 | 5500
    2 | 5764
    

    所以AuthorizationContext也被跨线程持久化。漂亮。

    最佳答案

    这实际上取决于您如何定义 session 和客户端。如果您从同一个进程进行两次调用,则 WCF 通信层很可能会在同一连接上对它们进行多路复用。

    您是否真的尝试过从完全不同的进程运行两个连接?你能达到同样的结果吗?

    关于.net - 来自不同客户端的调用之间未清除 WCF AuthorizationContext。 (原为 : When does a WCF service session actually end? ),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1189818/

    相关文章:

    c# - mscorlib 中未处理的异常

    c# - .NET 外部通信

    c# - 如何在对象中保存 session 变量?

    c# - Serial port write究竟是如何从缓冲区写入数据的呢?

    c# - 滚动条,如果 Items 超过 itemsControl 内部

    c# - 你能从 C++ 运行 C# 代码吗?

    .net - 强制 EF POCO 实体相关集合上的 linq-to-entities(类似于 EntityCollection<>)

    c# - WCF 服务 - 无法调用服务

    php - 我应该在 CodeIgniter 中的哪里初始化 session 库?

    asp.net - 访问 ActionFilterAttribute 中的 Session.SessionID