2009-07-20 6 views
9

私はRESTful Webサービスを持つことができるようにWCFを拡張しようとしています。それぞれの操作で、値がLogin()メソッドを呼び出すために使用するHTTP Authorizationヘッダーの検証を実行します。カスタムIOperationInvokerをいつどこで設定するのですか?

ログインが完了した後、適切なHTTPステータスコードを使用してカスタムの「アクセス拒否」メッセージで返信します。セキュリティ例外がスローされた場合は、操作の対応するメソッドのチェックを呼び出します。

これを考慮して

、私は(DispatchOperation.Invokerプロパティを設定)各操作にIOperationInvokerのimplementaionを適用することIEndpointBehaviorを実装する良いアイデアだと思いました。

私はデコレータのデザインを使用してIOperationInvokerを実施することを決定しました私の実装では、メソッドの呼び出しが委譲されるコンストラクタに別のIOperationInvokerが必要です。私はすでに必要な動作(WebHttpBehavior)私は一つだけbeaviorを使用するこの方法を拡張することによりIEndpointBehaviorを実施することを決定した

public class BookSmarTkOperationInvoker : IOperationInvoker{ 

    private readonly IOperationInvoker invoker; 

    public BookSmarTkOperationInvoker(IOperationInvoker decoratee) 
    { 
     this.invoker = decoratee; 
    } 

    public object[] AllocateInputs() 
    { 
     return this.invoker.AllocateInputs(); 
    } 

    public object Invoke(object instance, object[] inputs, out object[] outputs) 
    { 
     BeforeOperation(); // Where there's code to perform the login using WebOperationContext.Current 
     object o = null; 
     try 
     { 
      o = this.invoker.Invoke(instance, inputs, out outputs); 
     } 
     catch (Exception exception) 
     { 
      outputs = null; 
      return AfterFailedOperation(exception); // Return a custom access denied response 
     } 

     return o; 
    } 

    public IAsyncResult InvokeBegin(object instance, object[] inputs, AsyncCallback callback, object state) 
    { 
     throw new Exception("The operation invoker is not asynchronous."); 
    } 

    public object InvokeEnd(object instance, out object[] outputs, IAsyncResult result) 
    { 
     throw new Exception("The operation invoker is not asynchronous."); 
    } 

    public bool IsSynchronous 
    { 
     get 
     { 
      return false; 
     } 
    } 
} 

は、これが私のIOperationInvokerImplementationです。ここで私が書いたコードだ:

public class BookSmarTkEndpointBehavior : WebHttpBehavior 
{ 
    public override void Validate(ServiceEndpoint endpoint) 
    { 
     base.Validate(endpoint); 
    } 

    public override void AddBindingParameters(ServiceEndpoint endpoint, BindingParameterCollection bindingParameters) 
    { 
     base.AddBindingParameters(endpoint, bindingParameters); 
    } 

    public override void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) 
    { 
     base.ApplyDispatchBehavior(endpoint, endpointDispatcher); 

     foreach (DispatchOperation operation in endpointDispatcher.DispatchRuntime.Operations) 
     { 
      IOperationInvoker defaultInvoker = operation.Invoker; 
      IOperationInvoker decoratorInvoker = new BookSmarTkOperationInvoker(defaultInvoker); 
      operation.Invoker = decoratorInvoker; 

      Console.Write("Before: " + ((object)defaultInvoker ?? "null")); 
      Console.WriteLine(" After: " + operation.Invoker); 
     } 
    } 

    public override void ApplyClientBehavior(ServiceEndpoint endpoint, ClientRuntime clientRuntime) 
    { 
     base.ApplyClientBehavior(endpoint, clientRuntime); 
     throw new Exception("The BookSmarTkEndointBehavior cannot be used in client endpoints."); 
    } 
} 

は、今ここで問題です:

  1. だけコンストラクタがIOperationInvokerに呼び出されている、他の方法のいずれもありません。
  2. decoratee IOperationInvoker(デコレータのコンストラクタで渡されるもの)はnullです。

他のいくつかの動作のコードが、後でOperationDispatcher.Invoker設定で別のIOperationInvokerを設定している可能性があります。したがって、私をオーバーライドします。これは私の状況をはっきりと説明します。

何が起こっているのですか?

私のサービスは自己ホスト型です。

あなたが見たい場合は、system.serviceModelの下のapp.configファイルにある設定をご覧ください。

<services> 
    <service name="BookSmarTk.Web.Service.BookSmarTkService"> 
    <host> 
     <baseAddresses> 
     <add baseAddress="http://localhost:8080/service"/> 
     </baseAddresses> 
    </host> 
    <endpoint 
     address="" 
     behaviorConfiguration="BookSmaTkEndpointBehavior" 
     binding="webHttpBinding" 
     bindingConfiguration="BookSmarTkBinding" 
     contract="BookSmarTk.Web.Service.BookSmarTkService"> 
    </endpoint> 
    </service> 
</services> 

<behaviors> 
    <serviceBehaviors> 
    <behavior name ="BookSmartkServiceBehavior"> 
     <serviceDebug httpHelpPageEnabled="true" httpHelpPageUrl="/help.htm" includeExceptionDetailInFaults="true" /> 
    </behavior> 
    </serviceBehaviors> 
    <endpointBehaviors> 
    <behavior name="BookSmaTkEndpointBehavior"> 
     <!--<webHttp/>--> 
     <bookSmarTkEndpointBehavior /> 
    </behavior> 
    </endpointBehaviors> 
</behaviors> 

<bindings> 
    <webHttpBinding> 
    <binding name="BookSmarTkBinding"> 
    </binding> 
    </webHttpBinding> 
</bindings> 

<extensions> 
    <behaviorExtensions> 
    <add name="bookSmarTkEndpointBehavior" type="BookSmarTk.Web.Service.BookSmarTkEndpointBehaviorElement, BookSmarTk.Web.Service, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null"/> 
    </behaviorExtensions> 
</extensions> 

これまでのところ、私はあなたに深く感謝しています。本当にありがとう!

答えて

2

私は同様のものを構築しています(私は思っています - すべてのコードを調べる時間がありません)が、別の方法でそれについて行ってきました。私は、次を使用しています、これを達成するために

  • アンIMessageInspectorを(クッキーからセッションIDを抽出し、キャッシュからセッションオブジェクトを取得し、この場合に)入ってくるHTTPリクエストメッセージのヘッダを読み取ること。
  • 独自のカスタム認証コードを実装するためのIPrincipalとIAuthorizationPolicyの組み合わせ(WCFは、[PrincipalPermission(SecurityAction.Demand、Role = "somerole")という属性を持つWebサービスメソッドへのリクエストに対して自分のコードを自動的に呼び出します] 'セット)。
  • Webサービスメソッドからキャッチされない例外を検出するIErrorHandler(認証が失敗した場合、つまりIPrincipalで実装するIsRoleメソッドがfalseを返した場合など)、拒否されたアクセス許可例外がスローされます。セキュリティで拒否された例外を検出すると、WebOperationContext.Currentを使用して、応答メッセージのカスタムHTTPエラーコードを設定できます。
  • カスタム動作(IContractBehavior - ただし、EndPointまたはServiceの動作など)を使用して、実行時にこれらのすべてを作成し、適切なエンドポイントにアタッチすることもできます。代わりにApplyDispatchBehavior()メソッドで呼び出し側を設定する
12

、あなたはIOperationBehaviorの実装行う必要があります。

public class MyOperationBehavior: IOperationBehavior 
{ 
    public void AddBindingParameters(OperationDescription operationDescription, BindingParameterCollection bindingParameters) 
    { 
    } 

    public void ApplyClientBehavior(OperationDescription operationDescription, ClientOperation clientOperation) 
    { 
    } 

    public void ApplyDispatchBehavior(OperationDescription operationDescription, DispatchOperation dispatchOperation) 
    { 
    dispatchOperation.Invoker = new BookSmarTkOperationInvoker(dispatchOperation.Invoker); 
    } 

    public void Validate(OperationDescription operationDescription) 
    { 
    } 
} 

をし、その後ApplyDispatchBehavior()で、あなたはその動作を設定する必要があります

public void ApplyDispatchBehavior(ServiceEndpoint endpoint, EndpointDispatcher endpointDispatcher) 
    { 
    foreach (var operation in endpoint.Contract.Operations) { 
     if (operation.Behaviors.Contains(typeof(MyOperationBehavior))) 
     continue; 

     operation.Behaviors.Add(new MyOperationBehavior()); 
    } 
    } 
+2

これをソリューションは私と一緒に働いた+1 –

関連する問題