2015-02-17 8 views
9

पर प्राधिकरण शीर्षलेख खो गया है प्रमाणीकरण करता है, प्रमाणीकरण करता है, प्राधिकरण शीर्षलेख उत्पन्न करता है, और API को कॉल करता है।रीडायरेक्ट

दुर्भाग्य से, मुझे 401 Unauthorized एपीआई पर GET अनुरोध के बाद त्रुटि मिलती है।

हालांकि, जब मैं फिडलर में यातायात को पकड़ता हूं और इसे फिर से चलाता हूं, तो एपीआई को कॉल सफल होता है और मैं वांछित 200 OK स्थिति कोड देख सकता हूं।

[Test] 
public void RedirectTest() 
{ 
    HttpResponseMessage response; 
    var client = new HttpClient(); 
    using (var authString = new StringContent(@"{username: ""theUser"", password: ""password""}", Encoding.UTF8, "application/json")) 
    { 
     response = client.PostAsync("http://host/api/authenticate", authString).Result; 
    } 

    string result = response.Content.ReadAsStringAsync().Result; 
    var authorization = JsonConvert.DeserializeObject<CustomAutorization>(result); 
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authorization.Scheme, authorization.Token); 
    client.DefaultRequestHeaders.Add("Accept", "application/vnd.host+json;version=1"); 

    response = 
     client.GetAsync("http://host/api/getSomething").Result; 
    Assert.True(response.StatusCode == HttpStatusCode.OK); 
} 

जब मैं इस कोड को चलाता हूं तो प्राधिकरण शीर्षलेख खो जाता है।

हालांकि, फिडलर में हेडर सफलतापूर्वक पारित हो गया है।

कोई विचार क्या मैं गलत कर रहा हूं?

+0

जब पुनर्निर्देशन होती है:

public class TemporaryRedirectHandler : DelegatingHandler { protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var response = await base.SendAsync(request, cancellationToken); if (response.StatusCode == HttpStatusCode.TemporaryRedirect) { var location = response.Headers.Location; if (location == null) { return response; } using (var clone = await CloneRequest(request, location)) { response = await base.SendAsync(clone, cancellationToken); } } return response; } private async Task<HttpRequestMessage> CloneRequest(HttpRequestMessage request, Uri location) { var clone = new HttpRequestMessage(request.Method, location); if (request.Content != null) { clone.Content = await CloneContent(request); if (request.Content.Headers != null) { CloneHeaders(clone, request); } } clone.Version = request.Version; CloneProperties(clone, request); CloneKeyValuePairs(clone, request); return clone; } private async Task<StreamContent> CloneContent(HttpRequestMessage request) { var memstrm = new MemoryStream(); await request.Content.CopyToAsync(memstrm).ConfigureAwait(false); memstrm.Position = 0; return new StreamContent(memstrm); } private void CloneHeaders(HttpRequestMessage clone, HttpRequestMessage request) { foreach (var header in request.Content.Headers) { clone.Content.Headers.Add(header.Key, header.Value); } } private void CloneProperties(HttpRequestMessage clone, HttpRequestMessage request) { foreach (KeyValuePair<string, object> prop in request.Properties) { clone.Properties.Add(prop); } } private void CloneKeyValuePairs(HttpRequestMessage clone, HttpRequestMessage request) { foreach (KeyValuePair<string, IEnumerable<string>> header in request.Headers) { clone.Headers.TryAddWithoutValidation(header.Key, header.Value); } } } 

आप इस तरह HttpClient का दृष्टांत हैं? आप पुनर्निर्देशन के लिए किस HTTP कोड का उपयोग करते हैं? – tia

+0

@tia मुझे 307 अस्थायी रीडायरेक्ट – Vadim

+0

प्राप्त नहीं है कि यह सुनिश्चित नहीं है कि [यह किसी प्रासंगिकता का है] (http://stackoverflow.com/questions/18914076/can-a-http-redirect-instruct-the-client-to-strip- एक-विशिष्ट-हेडर-से-द-एनई) – pixelbadger

उत्तर

31

इस व्यवहार का अनुभव करने का कारण यह है कि यह डिज़ाइन द्वारा है।

अधिकांश HTTP क्लाइंट (डिफ़ॉल्ट रूप से) रीडायरेक्ट का पालन करते समय प्राधिकरण शीर्षलेख को हटा दें।

एक कारण सुरक्षा है। क्लाइंट को अविश्वसनीय तृतीय पक्ष सर्वर पर रीडायरेक्ट किया जा सकता है, जिसे आप अपने प्राधिकरण टोकन को प्रकट नहीं करना चाहते हैं।

आप क्या कर सकते हैं यह पता लगाया गया है कि रीडायरेक्ट हुआ है और सीधे सही स्थान पर अनुरोध को फिर से जारी करें।

आपका एपीआई 401 Unauthorized लौट रहा है यह इंगित करने के लिए कि प्राधिकरण शीर्षलेख गुम है (या अधूरा)। मुझे लगता है कि प्राधिकरण जानकारी अनुरोध में मौजूद है, लेकिन एक ही एपीआई 403 Forbidden देता है लेकिन यह गलत है (गलत उपयोगकर्ता नाम/पासवर्ड)।

यदि ऐसा है, तो आप 'रीडायरेक्ट/गायब प्राधिकरण शीर्षलेख' संयोजन का पता लगा सकते हैं और अनुरोध भेज सकते हैं।


यहाँ यह करने के लिए फिर से लिखा सवाल से कोड है:

[Test] 
public void RedirectTest() 
{ 
    // These lines are not relevant to the problem, but are included for completeness. 
    HttpResponseMessage response; 
    var client = new HttpClient(); 
    using (var authString = new StringContent(@"{username: ""theUser"", password: ""password""}", Encoding.UTF8, "application/json")) 
    { 
     response = client.PostAsync("http://host/api/authenticate", authString).Result; 
    } 

    string result = response.Content.ReadAsStringAsync().Result; 
    var authorization = JsonConvert.DeserializeObject<CustomAutorization>(result); 

    // Relevant from this point on. 
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue(authorization.Scheme, authorization.Token); 
    client.DefaultRequestHeaders.Add("Accept", "application/vnd.host+json;version=1"); 

    var requestUri = new Uri("http://host/api/getSomething"); 
    response = client.GetAsync(requestUri).Result; 

    if (response.StatusCode == HttpStatusCode.Unauthorized) 
    { 
     // Authorization header has been set, but the server reports that it is missing. 
     // It was probably stripped out due to a redirect. 

     var finalRequestUri = response.RequestMessage.RequestUri; // contains the final location after following the redirect. 

     if (finalRequestUri != requestUri) // detect that a redirect actually did occur. 
     { 
      if (IsHostTrusted(finalRequestUri)) // check that we can trust the host we were redirected to. 
      { 
       response = client.GetAsync(finalRequestUri).Result; // Reissue the request. The DefaultRequestHeaders configured on the client will be used, so we don't have to set them again. 
      } 
     } 
    } 

    Assert.True(response.StatusCode == HttpStatusCode.OK); 
} 


private bool IsHostTrusted(Uri uri) 
{ 
    // Do whatever checks you need to do here 
    // to make sure that the host 
    // is trusted and you are happy to send it 
    // your authorization token. 

    if (uri.Host == "host") 
    { 
     return true; 
    } 

    return false; 
} 

ध्यान दें कि आप finalRequestUri का मूल्य बचाने के लिए और भविष्य के अनुरोधों के लिए इसका इस्तेमाल करते हैं अतिरिक्त अनुरोध शामिल से बचने के लिए कर सकता है पुनः प्रयास में। हालांकि यह एक अस्थायी रीडायरेक्ट है, इसलिए आपको हर बार मूल स्थान पर अनुरोध जारी करना चाहिए।

+0

महान उत्तर के लिए धन्यवाद। उदाहरण बहुत उपयोगी है। – Vadim

+0

स्पष्टीकरण के लिए धन्यवाद। – jNet

0

मुझे एक ही समस्या थी, लेकिन काफी समान नहीं थी। मेरे मामले में, मुझे रीडायरेक्ट समस्या भी थी, लेकिन ओएथ के साथ सुरक्षा लागू की गई है, जिसमें द्वितीयक, लेकिन संबंधित समस्या भी होती है, जो टोकन कभी-कभी समाप्त हो जाती है।

कारण है कि, मैं कॉन्फ़िगर करने के लिए एक HttpClient स्वचालित रूप से जाने के लिए और OAuth टोकन ताज़ा जब यह, एक 401 Unauthorized प्रतिक्रिया मिलती है इस एक रीडायरेक्ट, या टोकन समाप्ति की वजह से होता है कि क्या की परवाह किए बिना करने में सक्षम होना चाहते हैं।

क्रिस ओ'नील द्वारा पोस्ट किया गया समाधान सामान्य कदमों को दिखाता है, लेकिन मैं उस व्यवहार को HttpClient ऑब्जेक्ट के अंदर एम्बेड करना चाहता था, इसके बजाय हमारे सभी HTTP कोड को एक अनिवार्य जांच के साथ घूमने के बजाय।हमारे पास बहुत सारे मौजूदा कोड हैं जो साझा HttpClient ऑब्जेक्ट का उपयोग करते हैं, इसलिए यदि मैं उस ऑब्जेक्ट के व्यवहार को बदल सकता हूं तो हमारे कोड को दोबारा करना बहुत आसान होगा।

ऐसा लगता है कि यह काम कर रहा है। मैंने अभी तक इसे प्रोटोटाइप किया है, लेकिन ऐसा लगता है कि यह काम कर रहा है। हमारे कोड बेस के ज्यादातर एफ # में है, इसलिए कोड एफ # में है:

open System.Net 
open System.Net.Http 

type TokenRefresher (refreshAuth, inner) = 
    inherit MessageProcessingHandler (inner) 

    override __.ProcessRequest (request, _) = request 

    override __.ProcessResponse (response, cancellationToken) = 
     if response.StatusCode <> HttpStatusCode.Unauthorized 
     then response 
     else 
      response.RequestMessage.Headers.Authorization <- refreshAuth() 
      inner.SendAsync(response.RequestMessage, cancellationToken).Result 

यह एक छोटे से वर्ग कि Authorization हैडर ताज़ा अगर यह एक 401 Unauthorized प्रतिक्रिया मिलती है का ध्यान रखता है। यह इंजेक्शन refreshAuth फ़ंक्शन का उपयोग करके रीफ्रेश करता है, जिसमें unit -> Headers.AuthenticationHeaderValue टाइप होता है।

चूंकि यह अभी भी प्रोटोटाइप कोड है, इसलिए मैंने आंतरिक SendAsync ब्लॉकिंग कॉल को कॉल किया है, जिससे इसे एक एसिंक वर्कफ़्लो का उपयोग करके इसे ठीक से कार्यान्वित करने के लिए पाठक को एक अभ्यास के रूप में छोड़ दिया जाता है।

refreshAuth नामक एक ताज़ा समारोह को देखते हुए, आप इस तरह एक नया HttpClient वस्तु बना सकते हैं:

let client = new HttpClient(new TokenRefresher(refreshAuth, new HttpClientHandler())) 

जवाब क्रिस ओ'नील द्वारा पोस्ट किया है कि नया URL सुरक्षित माना जाता है की जाँच करने के ख्याल रखता है। मैंने उस सुरक्षा पर विचार छोड़ दिया है, लेकिन आपको अनुरोध को पुनः प्रयास करने से पहले एक समान जांच सहित दृढ़ता से विचार करना चाहिए।

+0

हालांकि यह एक अलग समस्या हल करता है (टोकन रीफ्रेश)। – MvdD

+0

@MvdD यह इस बात पर निर्भर करता है कि आप 'refreshAuth' को कैसे कार्यान्वित करते हैं। –

+0

निश्चित रूप से, लेकिन आम तौर पर आप टोकन को रीफ्रेश नहीं करना चाहते हैं जब तक कि यह समाप्त नहीं हो जाता है। ओपी मामले में, टोकन की समयसीमा समाप्त नहीं हुई थी, लेकिन पुनर्निर्देशित अनुरोध से छोड़ी गई थी। – MvdD

1

मैं स्वचालित रीडायरेक्ट व्यवहार बंद कर दूंगा और एक क्लाइंट हैंडर बनाउंगा जो अस्थायी रीडायरेक्ट से निपटने वाले कोड को छुपाता है। HttpClient कक्षा आपको DelegatingHandler से स्थापित करने की अनुमति देती है, जिससे आप प्रतिक्रिया के अनुरोध को संशोधित कर सकते हैं।

var handler = new TemporaryRedirectHandler() 
{ 
    InnerHandler = new HttpClientHandler() 
    { 
     AllowAutoRedirect = false 
    } 
}; 

HttpClient client = new HttpClient(handler); 
+0

आप स्वचालित रीडायरेक्ट क्यों बंद कर देंगे? –

+0

@MarkSeemann तो मैं उन्हें अपने द्वारा स्थापित क्लाइंट हैंडलर में स्वयं संभाल सकता हूं। – MvdD

संबंधित मुद्दे