2012-08-19 13 views
47

बुनियादी प्रमाणीकरण के लिए मैं एक कस्टम HttpMessageHandler उदाहरण डैरिन दिमित्रोव के जवाब यहाँ में दिखाया गया है के आधार पर लागू किया है: https://stackoverflow.com/a/11536349/270591मैं कस्टम वेबैपी HttpMessageHandler में उपयोगकर्ता प्रिंसिपल को सुरक्षित रूप से कैसे सेट कर सकता हूं?

कोड उपयोगकर्ता नाम और भूमिकाओं और फिर टाइप GenericPrincipal का एक उदाहरण principal बनाता है वर्तमान प्राचार्य को यह प्रिंसिपल सेट धागे की:

Thread.CurrentPrincipal = principal; 
एक ApiController विधि प्रिंसिपल नियंत्रकों User प्रॉपर्टी एक्सेस द्वारा पढ़ा जा सकता बाद में

:

public class ValuesController : ApiController 
{ 
    public void Post(TestModel model) 
    { 
     var user = User; // this should be the principal set in the handler 
     //... 
    } 
} 

यह ठीक काम करने के लिए जब तक मैं हाल ही में एक कस्टम MediaTypeFormatter तो जैसे Task पुस्तकालय का उपयोग करता है जोड़ा लग रहा था:

public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, 
    HttpContent content, IFormatterLogger formatterLogger) 
{ 
    var task = Task.Factory.StartNew(() => 
    { 
     // some formatting happens and finally a TestModel is returned, 
     // simulated here by just an empty model 
     return (object)new TestModel(); 
    }); 
    return task; 
} 

(मैं इस दृष्टिकोण कुछ नमूना कोड से ReadFromStreamAsync में Task.Factory.StartNew के साथ एक कार्य शुरू कर दिया है। है प्रिंसिपल अब और मैं में सेट किया है नहीं नियंत्रक विधि में User प्रिंसिपल - यह गलत है और समस्या के लिए शायद एकमात्र कारण है)

अब, "कभी-कभी" - और मेरे लिए यह यादृच्छिक प्रतीत होता है MessageHandler, यानी उपयोगकर्ता नाम, Authenticated ध्वज और भूमिकाएं सभी खो गई हैं। ऐसा लगता है कि कस्टम MediaTypeFormatter संदेशहैंडलर और नियंत्रक विधि के बीच धागे में परिवर्तन का कारण बनता है। मैंने MessageHandler में और नियंत्रक विधि में Thread.CurrentThread.ManagedThreadId के मानों की तुलना करके इसकी पुष्टि की है। "कभी-कभी" वे अलग होते हैं और फिर प्रिंसिपल "खो गया" होता है।

मैं Thread.CurrentPrincipal की स्थापना किसी भी तरह नियंत्रक विधि के लिए और में this blog post अनुरोध गुण कस्टम MessageHandler से सुरक्षित रूप से प्राचार्य को हस्तांतरण करने के लिए एक विकल्प के लिए अब देखा है उपयोग किया जाता है:

request.Properties.Add(HttpPropertyKeys.UserPrincipalKey, 
    new GenericPrincipal(identity, new string[0])); 

मुझे लगता है कि परीक्षण करने के लिए चाहता था, लेकिन ऐसा लगता है कि HttpPropertyKeys वर्ग (जो नामस्थान System.Web.Http.Hosting में है) में हाल ही में वेबएपी संस्करणों में रिलीज UserPrincipalKey संपत्ति नहीं है (रिलीज उम्मीदवार और अंतिम सप्ताह भी अंतिम रिलीज)।

मेरा प्रश्न है: मैं ऊपर अंतिम कोड स्निपेट कैसे बदल सकता हूं ताकि यह वर्तमान वेबएपीआई संस्करण के साथ काम कर सके? या आम तौर पर: मैं एक कस्टम संदेश हैंडलर में उपयोगकर्ता प्रिंसिपल कैसे सेट कर सकता हूं और इसे नियंत्रक विधि में विश्वसनीय रूप से एक्सेस कर सकता हूं?

संपादित

यह here उल्लेख किया गया है कि "HttpPropertyKeys.UserPrincipalKey ... “MS_UserPrincipal” ले कर जाता है", तो मैं का उपयोग करने की कोशिश की:

request.Properties.Add("MS_UserPrincipal", 
    new GenericPrincipal(identity, new string[0])); 

लेकिन यह के रूप में मैं उम्मीद काम नहीं करता है: ApiController.User संपत्ति में उपरोक्त Properties संग्रह में प्रिंसिपल शामिल नहीं है।

+0

मैं सुझाव देता हूं कि यह https://github.com/thinktecture/Thinktecture.IdentityModel.45 –

उत्तर

72

एक नया धागा पर प्रिंसिपल खोने की समस्या यहां बताया गया है:

http://leastprivilege.com/2012/06/25/important-setting-the-client-principal-in-asp-net-web-api/

महत्वपूर्ण: एएसपी.नेट वेब एपीआई में क्लाइंट प्रिंसिपल को सेट करना

एएसपी.NET में गहरे दफन किए गए कुछ दुर्भाग्यपूर्ण तंत्रों के कारण, थ्रेड स्थापित करें। वेब एपीआई वेब होस्टिंग में वर्तमान प्रिंसिपल पर्याप्त नहीं है।

एएसपी.NET में होस्टिंग करते समय, थ्रेड। कंटेंट प्रिंसिपल को को HttpContext.Current.User के साथ नए धागे बनाते समय ओवरराइड किया जा सकता है। इसका अर्थ है आपको प्रिंटर को थ्रेड और HTTP संदर्भ दोनों पर सेट करना होगा।

और यहाँ: http://aspnetwebstack.codeplex.com/workitem/264

आज, आप दोनों उपयोगकर्ता प्रिंसिपल के लिए निम्न में से स्थापित करने के लिए यदि आप एक कस्टम संदेश हैंडलर का उपयोग वेब की मेजबानी की स्थिति में प्रमाणीकरण प्रदर्शन करने के लिए की आवश्यकता होगी।

IPrincipal principal = new GenericPrincipal(
    new GenericIdentity("myuser"), new string[] { "myrole" }); 
Thread.CurrentPrincipal = principal; 
HttpContext.Current.User = principal; 

मैं संदेश हैंडलर के लिए अंतिम पंक्ति HttpContext.Current.User = principal (जरूरत using System.Web;) और ApiController है अब सही प्रिंसिपल हमेशा, भले ही धागे में काम की वजह से बदल गया है में User संपत्ति को शामिल किया है MediaTypeFormatter।

संपादित

बस इसे जोर देना: जब WebAPI ASP.NET/IIS में होस्ट किया गया है HttpContext की वर्तमान उपयोगकर्ता के प्रिंसिपल की स्थापना केवल आवश्यक है। स्वयं-होस्टिंग के लिए यह आवश्यक नहीं है (और संभव नहीं है क्योंकि HttpContext एक एएसपी.नेट निर्माण है और स्वयं होस्ट होने पर मौजूद नहीं है)।

5

संदर्भ स्विच से बचने के लिए के बजाय एक TaskCompletionSource<object> उपयोग का प्रयास करें मैन्युअल रूप से आपका MediaTypeFormatter में किसी अन्य कार्य शुरू करने से:

public override Task<object> ReadFromStreamAsync(Type type, Stream readStream, HttpContent content, IFormatterLogger formatterLogger) 
{ 
    var tcs = new TaskCompletionSource<object>(); 

    // some formatting happens and finally a TestModel is returned, 
    // simulated here by just an empty model 
    var testModel = new TestModel(); 

    tcs.SetResult(testModel); 
    return tcs.Task; 
} 
+2

यह काम करता है, लेकिन मैं काम करने के लिए कार्यों और धागे के उपयोग से सावधान रहना चाहता हूं सुरक्षा सुविधा बरकरार है। मुझे एक और समाधान मिला है, मेरा अपना जवाब यहां देखें। – Slauma

+0

@ डारिन डिमिट्रोव, मैंने 2012 बनाम आरटीएम और एएसपीनेट वेब एपीआई और एचटीपीप्रॉपर्टीकी के नवीनतम बिट्स स्थापित किए हैं। यूसर प्रिंसिपलकी वाक्यविन्यास त्रुटि देता है। ऑब्जेक्ट ब्राउज़र में क्लास देखने से पता चलता है कि यह कुंजी अंतिम रिलीज में मौजूद नहीं है। कोई विचार मैं और क्या उपयोग कर सकता हूं? –

+1

आप 'HttpPropertyKeys.UserPrincipalKey' का उपयोग क्यों करना चाहते हैं?मेरे जवाब में आपने इसका उपयोग कब देखा? तो इसका इस्तेमाल न करें। –

4

MessageHandler आप HttpRequestMessageExtensionMethods.SetUserPrincipal विस्तार विधि System.ServiceModel.Channels में परिभाषित फोन करके MS_UserPrincipal संपत्ति जोड़ सकते हैं अपने कस्टम का उपयोग करना:

protected override Task<HttpResponseMessage> SendAsync(
    HttpRequestMessage request, CancellationToken cancellationToken) 
{ 
    var user = new GenericPrincipal(new GenericIdentity("UserID"), null); 
    request.SetUserPrincipal(user); 
    return base.SendAsync(request, cancellationToken); 
} 

ध्यान दें कि यह केवल अनुरोध के गुण संग्रह के लिए इस संपत्ति कहते हैं, यह नहीं बदलता है उपयोगकर्ता ApiController से जुड़ा हुआ है।

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

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