2011-10-06 7 views
5

나는 다음과 같이 OperationContext 보내는 메시지 헤더에 API 키를 부착하기 위해 노력하고있어 :추가 및 데이터 검색

public static void AddApikeyToHeader(string apikey, IContextChannel channel, string address) 
    { 
     using (OperationContextScope scope = new OperationContextScope(channel)) 
     { 
      MessageHeader header = MessageHeader.CreateHeader("apikey", address, apikey); 
      OperationContext.Current.OutgoingMessageHeaders.Add(header); 

     } 
    } 

를하지만 내가 어떻게 서버 측에서 헤더를 검색하는 방법 아무 생각이 없다 . 나는 서비스 권한 부여 관리자를 사용하고 있는데 나는 현재 운영 상황을 얻고 같이 헤더를 검색하려고 :

public string GetApiKey(OperationContext operationContext) 
    { 
     var request = operationContext.RequestContext.RequestMessage; 

     var prop = (HttpRequestMessageProperty)request.Properties[HttpRequestMessageProperty.Name]; 

     return prop.Headers["apikey"]; 
    } 

을하지만, 거기에 첨부 된 apiKey에 헤더가 없습니다. 또한, 디버깅을 할 때 operationContext를 검사 할 때 어디에도 내 apikey 헤더가 보이지 않는 것 같습니다. 아무도 내가 잘못 가고있는 것을 볼 수 있습니까?

답변

14

:

Guid apiKey = 
OperationContext.Current.IncomingMessageHeaders.GetHeader<Guid>("apiKey", "ns"); 
+0

고마워요! 컨텍스트 범위의 평생 동안 내 서비스 호출을하지 못했기 때문에 문제가 발생했다고 생각했습니다! – Dimitar

+0

서비스 채널이란 무엇입니까? IMyServiceChannel? – PositiveGuy

+0

IMyServiceChannel은 클라이언트와 서버 간의 통신 채널 인터페이스입니다. –

0

이 질문을보십시오 : How to add a custom HTTP header to every WCF call?? 그것은 당신의 솔루션을 포함 할 수 있습니다.

당신은이 방법으로 사용자 정의 헤더를 추가 할 수 있습니다
+0

네, 그걸 보았습니다. 제가 필요로하는 서비스 인증 관리자를 계속 유지하려고합니다. – Dimitar

1

난 당신이 몇 가지를 사용하여 서비스를 사용하기 위해 노력하고 있으리라 믿고있어 :

using (ChannelFactory<IMyServiceChannel> factory = 
     new ChannelFactory<IMyServiceChannel>(new NetTcpBinding())) 
     { 
     using (IMyServiceChannel proxy = factory.CreateChannel(...)) 
     { 
      using (OperationContextScope scope = new OperationContextScope(proxy)) 
      { 
      Guid apiKey = Guid.NewGuid(); 
      MessageHeader<Guid> mhg = new MessageHeader<Guid>(apiKey); 
      MessageHeader untyped = mhg.GetUntypedHeader("apiKey", "ns"); 
      OperationContext.Current.OutgoingMessageHeaders.Add(untyped); 

      proxy.DoOperation(...); 
      } 
     }      
    } 

그리고 서비스면, 당신은 같은 헤더를 얻을 수 있습니다 HTTP 프로토콜 기반 전송 (SOAP, REST 등). 또한 원하는 API 키를 사용하여 호출자에게 권한을 부여하는 것으로 가정합니다. 이 두 가지 조건이 모두 귀하의 질문에 적용된다면, 계속 읽어보십시오.

나는 최근에 API 키를 전달하지 않고 HTTP 사용자 정의 헤더를 사용하여 사용자 이름/암호 해시 조합을 전달하는 비슷한 문제를 해결해야했습니다. 나는 궁극적으로 WCF 파이프 라인에 멋지게 접하는 Web.config에서 구성한 사용자 지정 인증 정책을 구현하여이를 해결했습니다.

아래 스 니펫은 시작하기에 충분해야합니다. 아마도 x-ms-credentials-XXX 헤더를 API 키를 나타내는 단일 헤더로 대체해야합니다.

internal class RESTAuthorizationPolicy : IAuthorizationPolicy 
{ 
    public RESTAuthorizationPolicy() 
    { 
    Id = Guid.NewGuid().ToString(); 
    Issuer = ClaimSet.System; 
    } 

    public bool Evaluate(EvaluationContext evaluationContext, ref object state) 
    { 
    const String HttpRequestKey = "httpRequest"; 
    const String UsernameHeaderKey = "x-ms-credentials-username"; 
    const String PasswordHeaderKey = "x-ms-credentials-password"; 
    const String IdentitiesKey = "Identities"; 
    const String PrincipalKey = "Principal"; 

    // Check if the properties of the context has the identities list 
    if (evaluationContext.Properties.Count > 0 || 
     evaluationContext.Properties.ContainsKey(IdentitiesKey) || 
     !OperationContext.Current.IncomingMessageProperties.ContainsKey(HttpRequestKey)) 
     return false; 

    // get http request 
    var httpRequest = (HttpRequestMessageProperty)OperationContext.Current.IncomingMessageProperties[HttpRequestKey]; 

    // extract credentials 
    var username = httpRequest.Headers[UsernameHeaderKey]; 
    var password = httpRequest.Headers[PasswordHeaderKey]; 

    // verify credentials complete 
    if (string.IsNullOrEmpty(username) || string.IsNullOrEmpty(password)) 
     return false; 

    // Get or create the identities list 
    if (!evaluationContext.Properties.ContainsKey(IdentitiesKey)) 
     evaluationContext.Properties[IdentitiesKey] = new List<IIdentity>(); 
    var identities = (List<IIdentity>) evaluationContext.Properties[IdentitiesKey]; 

    // lookup user 
    using (var con = ServiceLocator.Current.GetInstance<IDbConnection>()) 
    { 
     using (var userDao = ServiceLocator.Current.GetDao<IUserDao>(con)) 
     { 
     var user = userDao.GetUserByUsernamePassword(username, password); 

     ... 
관련 문제