2010-09-02 162 views
6

我每次發送到WCF的請求都需要傳遞一個值,並檢查服務器上的值並決定是否發出請求,任何人都可以寫一個例子嗎?我不知道那是怎麼回事即將實施WCF和身份驗證

case: 即時生成基於客戶端硬件的密鑰,我想發送該密鑰到服務器與每個請求,以檢查密鑰是否被接受在服務器數據庫然後決定處理請求與否。

在此先感謝。

+1

參見http://stackoverflow.com/questions/964433/how-to-add-a-custom-header-to-every-wcf-calls自動傳遞數據作爲報頭。不過,我不知道如何在服務器上自動檢查它,但我希望有一個鉤子。 – Rup 2010-09-02 08:37:24

回答

1

首先我們需要實現在客戶端行爲,並檢查送鑰匙到客戶端進行身份驗證:

class AuthenticationBehaviour : IEndpointBehavior 
{ 
    #region IEndpointBehavior Members 

    public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) 
    { 
    } 

    public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime) 
    { 
     AuthenticationMessageInspector inspector = new AuthenticationMessageInspector(); 
     clientRuntime.MessageInspectors.Add(inspector); 
    } 

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher) 
    { 
     //AuthenticationMessageInspector inspector = new AuthenticationMessageInspector(); 
     //endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector); 
    } 

    public void Validate(ServiceEndpoint endpoint) 
    { 
    } 

    class AuthenticationMessageInspector : IClientMessageInspector 
{ 
    private const string HeaderKey = "Authentication"; 

    public object BeforeSendRequest(ref Message request, IClientChannel channel) 
    { 

     if (Session.MachineId == 0) 
     { 
      Session.MachineId = LicenseGenerator.GenerateLicense(); 
     } 


     request.Headers.Add(MessageHeader.CreateHeader(HeaderKey, string.Empty, Session.MachineId)); 
     return null; 
    } 

    public void AfterReceiveReply(ref Message reply, object correlationState) 
    { 

    } 
} 

現在我們需要實現在服務器端(WCF服務)的行爲和督察檢查的每個請求,並提取頭然後驗證它:

public class AuthenticationBehaviour : IEndpointBehavior 
{ 
    #region IEndpointBehavior Members 

    public void AddBindingParameters(ServiceEndpoint endpoint, System.ServiceModel.Channels.BindingParameterCollection bindingParameters) 
    { 
    } 

    public void ApplyClientBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.ClientRuntime clientRuntime) 
    { 
     //AuthenticationMessageInspector inspector = new AuthenticationMessageInspector(); 
     //clientRuntime.MessageInspectors.Add(inspector); 
    } 

    public void ApplyDispatchBehavior(ServiceEndpoint endpoint, System.ServiceModel.Dispatcher.EndpointDispatcher endpointDispatcher) 
    { 
     AuthenticationMessageInspector inspector = new AuthenticationMessageInspector(); 
     endpointDispatcher.DispatchRuntime.MessageInspectors.Add(inspector); 
     //Console.WriteLine("Dispatcher Applied!"); 
    } 

    public void Validate(ServiceEndpoint endpoint) 
    { 
    } 

    #endregion 
} 

    public class AuthenticationMessageInspector : IDispatchMessageInspector 

{ 

    #region Members 
    private string conStr = "", commStr = ""; 
    public IDbConnection Connection { get; set; } 
    public IDbCommand Command { get; set; } 
    public IDataReader Reader { get; set; } 

    #endregion   
    private const string HeaderKey = "Authentication"; 
    public object AfterReceiveRequest(ref Message request, IClientChannel channel, InstanceContext instanceContext) 
    { 
     //Console.WriteLine("recieved Request! "); 
     int headerIndex = request.Headers.FindHeader(HeaderKey, string.Empty); 
     if (headerIndex < 0 || string.IsNullOrEmpty(request.Headers.GetHeader<String>(headerIndex))) 
     { 

      throw (new Exception("Access Denied!\n")); 
      return null; 
     } 


     bool valid = Validate(request.Headers.GetHeader<String>(headerIndex)); 
     if (!valid) 
     { 
      Console.WriteLine("recieved Request! From " + request.Headers.GetHeader<String>(headerIndex) + " and Access Denied!\n"); 
      throw (new Exception("Access Denied!\n" + request.Headers.GetHeader<String>(headerIndex) + " License Number is not athourized! "));   
     } 
     if (headerIndex != -1) 
     { 
      Console.WriteLine("recieved Request! From " + request.Headers.GetHeader<String>(headerIndex)); 
     } 
     return null; 

    } 

    public void BeforeSendReply(ref Message reply, object correlationState) 
    { 

    } 
} 

現在允許登記的行爲:

  _routingHost.Description.Endpoints[0].Behaviors.Add(new Gateway.Controllers.AuthenticationBehaviour()); 
_routingHost.Open(); 

這是它的感謝。

2

您正在尋找訊息檢查員。檢查這個article

編輯:

提到的方法是你的情況中最容易的方法。您將創建客戶端消息檢查器以添加自定義標頭並分派消息檢查器來提取標頭和驗證密鑰。如果密鑰無效,則會拋出異常。

乾淨的解決方案是創建custom tokencutom credentials,但它非常複雜,因此除非您想深入瞭解WCF安全實現使用消息檢查器。

+0

im生成一個基於客戶端的硬件的密鑰,我想發送該密鑰到服務器與每個請求,以檢查密鑰是否被接受在服務器數據庫,然後決定處理請求或不 – Stacker 2010-09-02 09:34:09

+0

所以它是一個身份驗證(只需檢查具有密鑰的客戶端是否可以訪問服務)或授權(不同的密鑰可以使用不同的操作集)? – 2010-09-02 09:58:27

+0

只需檢查具有密鑰的客戶端是否可以訪問服務 – Stacker 2010-09-02 10:17:36

1

我已經實現了這樣的事情來處理一些特別的「自定義」身份驗證,其中基於數據庫狀態允許或拒絕方法。它使用PerSession實現,它允許您避免每次都傳遞該密鑰,因爲您可以在執行期間維護代理。它還通過消除重複實例化代理的開銷(可能不是問題取決於您的設計)來提供一些性能優勢。

  1. 用「PerSession」 [ServiceBehavior(InstanceContextMode = InstanceContextMode.PerSession)]的InstanceContextMode
  2. 請提供服務的初始化方法,該方法接受鍵,並保持對它的引用實施您服務。
  3. 在您的服務方法中,檢查該密鑰,其他條件等以確定您需要執行的操作。
  4. 現在,當您實例化客戶端代理時,首先調用該初始化方法傳遞該密鑰,然後從該點開始,您可以繼續在沒有它的情況下進行調用。
+0

其實我已經實現它了,非常感謝你幫助我,我用了一種不同的方法,因爲我很快發佈了一個答案 – Stacker 2010-09-07 14:52:24

0

我在試圖在WCF Rest服務上實現身份驗證機制時談到了這篇文章,我試圖在自定義消息檢查器方法AfterReceiveRequest上獲取身份驗證頭,但遇到了使用提供的System.ServiceModel檢索頭的問題。渠道。消息對象(在方法簽名請求VAR)

public object AfterReceiveRequest(ref Message request, IClientChannel channel, 
    InstanceContext instanceContext) 
    Dim headerIndex = request.Headers.FindHeader(HeaderKey, String.Empty) 

的headerIndex將總是-1,考慮到本我研究,發現有一個擴展方法的消息類,其允許消息轉換爲對象類型System.Net.Http.HttpRequestMessage。要做到這一點,所有需要的是導入下列程序集:System.ServiceModel.Channel,System.Net.Http。

Dim httpReq As System.Net.Http.HttpRequestMessage = request.ToHttpRequestMessage() 

Dim authValue As String 
If httpReq.Headers.Contains(HeaderKey) Then 
    authValue = httpReq.Headers.GetValues(HeaderKey)(0) 
End If