2012-09-27 11 views
29

मैं ASP.NET का उपयोग करके विकसित एक वेब अनुप्रयोग के लिए कुछ असामान्य आवश्यकताओं को पूरा करने के लिए एक कस्टम प्राधिकरण/प्रमाणीकरण दिनचर्या बनाने के लिए से इनहेरिट हूँ System.Web.Http.AuthorizeAttribute के लिए ASP.NET वेब एपीआई AuthorizeAttribute अनुकूलित कैसे एमवीसी 4. यह वेब क्लाइंट से अजाक्स कॉल के लिए उपयोग की जाने वाली वेब एपीआई में सुरक्षा जोड़ता है। आवश्यकताएँ हैं:असामान्य आवश्यकताओं

  1. उपयोगकर्ता जब भी किसी लेन-देन के लिए प्रदर्शन को सत्यापित करने के बाद किसी लॉग ऑन और दूर चला गया है और कुछ किसी कार्य केंद्र के लिए ऊपर चला गया नहीं किया है लॉगऑन करना होगा।
  2. भूमिकाओं को प्रोग्राम समय पर वेब सेवा विधियों को असाइन नहीं किया जा सकता है। उन्हें रन टाइम पर असाइन किया जाना चाहिए ताकि व्यवस्थापक इसे कॉन्फ़िगर कर सके। यह जानकारी सिस्टम डेटाबेस में संग्रहीत है।

वेब ग्राहक एक single page application (SPA) तो ठेठ रूपों प्रमाणीकरण इतनी अच्छी तरह से काम नहीं करता है, लेकिन मैं के रूप में मैं आवश्यकताओं को पूरा कर सकते हैं ASP.NET सुरक्षा ढांचे के रूप में ज्यादा पुन: उपयोग कोशिश कर रहा हूँ। अनुकूलित AuthorizeAttribute वेब सेवा विधि से कौन सी भूमिकाएं जुड़ी हैं यह निर्धारित करने के लिए आवश्यकता 2 के लिए बहुत अच्छा काम करता है। मैं तीन पैरामीटर, एप्लिकेशन का नाम, संसाधन नाम और ऑपरेशन स्वीकार करता हूं यह निर्धारित करने के लिए कि कौन सी भूमिकाएं किसी विधि से जुड़ी हैं।

public class DoThisController : ApiController 
{ 
    [Authorize(Application = "MyApp", Resource = "DoThis", Operation = "read")] 
    public string GetData() 
    { 
     return "We did this."; 
    } 
} 

मैं भूमिकाओं हो और उपयोगकर्ता को प्रमाणित करने OnAuthorization विधि ओवरराइड। चूंकि उपयोगकर्ता को प्रत्येक लेनदेन के लिए प्रमाणीकृत होना पड़ता है, इसलिए मैं उसी चरण में प्रमाणीकरण और प्रमाणीकरण करके पीछे और आगे की चपेट में कमी करता हूं। मुझे मूल प्रमाणीकरण का उपयोग करके वेब क्लाइंट से उपयोगकर्ता प्रमाण-पत्र प्राप्त होते हैं जो HTTP शीर्षलेख में एन्क्रिप्टेड प्रमाण-पत्र पास करता है। तो मेरी OnAuthorization विधि इस प्रकार है:

public override void OnAuthorization(HttpActionContext actionContext) 
{ 

    string username; 
    string password; 
    if (GetUserNameAndPassword(actionContext, out username, out password)) 
    { 
     if (Membership.ValidateUser(username, password)) 
     { 
      FormsAuthentication.SetAuthCookie(username, false); 
      base.Roles = GetResourceOperationRoles(); 
     } 
     else 
     { 
      FormsAuthentication.SignOut(); 
      base.Roles = ""; 
     } 
    } 
    else 
    { 
     FormsAuthentication.SignOut(); 
     base.Roles = ""; 
    } 
    base.OnAuthorization(actionContext); 
} 

GetUserNameAndPassword HTTP हेडर से साख प्राप्त करता है। मैं फिर सदस्यता का उपयोग करता हूं। प्रमाणीकरण मान्य करने के लिए ValidateUser। मेरे पास एक कस्टम सदस्यता प्रदाता और भूमिका प्रदाता है जो एक कस्टम डेटाबेस हिट करने के लिए प्लग इन है। यदि उपयोगकर्ता प्रमाणीकृत है तो मैं संसाधन और संचालन के लिए भूमिकाएं पुनर्प्राप्त करता हूं। वहां से मैं प्रमाणीकरण प्रक्रिया को पूरा करने के लिए आधार ऑन प्राधिकरण का उपयोग करता हूं। यहां वह जगह है जहां यह टूट जाता है।

यदि उपयोगकर्ता प्रमाणित है तो मैं उपयोगकर्ता को लॉग इन करने के लिए मानक प्रपत्र प्रमाणीकरण विधियों का उपयोग करता हूं (FormsAuthentication.SetAuthCookie) और यदि वे विफल हो जाते हैं तो मैं उन्हें लॉग आउट करता हूं (फॉर्म प्रमाणीकरण। साइनऑट)। लेकिन समस्या यह है कि आधार ऑन प्राधिकरण कक्षा में तक पहुंच नहीं है प्रिंसिपल अद्यतन किया गया है ताकि मान्य किया गया सही मान पर सेट है। यह हमेशा एक कदम पीछे है। और मेरा अनुमान है कि यह कुछ कैश किए गए मान का उपयोग कर रहा है जो वेब क्लाइंट के लिए एक राउंड ट्रिप होने तक अद्यतन नहीं होता है।

तो यह सब मेरी विशिष्ट सवाल यह है कि जो अप करने के लिए जाती है, तो कुकीज़ का उपयोग किए बिना वर्तमान प्रधान के लिए सही मान को IsAuthenticated स्थापित करने के लिए एक और तरीका है? ऐसा लगता है कि कुकीज वास्तव में इस विशिष्ट परिदृश्य में लागू नहीं होती हैं जहां मुझे हर बार प्रमाणित करना होता है।कारण मैं जानता हूँ कि IsAuthenticated सही मान पर सेट नहीं है मैं भी इस के लिए HandleUnauthorizedRequest विधि ओवरराइड है:

protected override void HandleUnauthorizedRequest(HttpActionContext filterContext) 
{ 
    if (((System.Web.HttpContext.Current.User).Identity).IsAuthenticated) 
    { 
     filterContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden); 
    } 
    else 
    { 
     base.HandleUnauthorizedRequest(filterContext); 
    } 
} 

यह मैं विफलता अगर वेब ग्राहक के लिए निषिद्ध का स्थिति कोड वापस लौट सकते हैं प्रमाणीकरण के बजाय प्राधिकरण की वजह से था और यह तदनुसार जवाब दे सकता है।

तो IsAuthenticated इस परिदृश्य में वर्तमान सिद्धांत के लिए स्थापित करने के लिए उचित तरीके क्या है?

उत्तर

33

मेरे परिदृश्य के लिए सबसे अच्छा समाधान आधार ऑनअधिकृतकरण को बाईपास करना प्रतीत होता है। चूंकि मुझे प्रत्येक बार कुकीज़ को प्रमाणित करना है और सिद्धांत को कैशिंग करना बहुत अधिक उपयोग नहीं है। तो यहाँ समाधान मैं के साथ आया है:

public override void OnAuthorization(HttpActionContext actionContext) 
{ 
    string username; 
    string password; 

    if (GetUserNameAndPassword(actionContext, out username, out password)) 
    { 
     if (Membership.ValidateUser(username, password)) 
     { 
      if (!isUserAuthorized(username)) 
       actionContext.Response = 
        new HttpResponseMessage(System.Net.HttpStatusCode.Forbidden); 
     } 
     else 
     { 
      actionContext.Response = 
       new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized); 
     } 
    } 
    else 
    { 
     actionContext.Response = 
      new HttpResponseMessage(System.Net.HttpStatusCode.BadRequest); 
    } 
} 

मैं भूमिकाओं बुलाया सत्यापित करने के लिए अपने ही विधि विकसित की isUserAuthorized और मैं आधार OnAuthorization किसी भी अधिक उपयोग नहीं कर रहा है, क्योंकि यह वर्तमान सिद्धांत की जाँच करता है यह देखने के लिए कि क्या यह प्रमाणीकृत है। IsAuthenticated केवल अनुमति देता है इसलिए मुझे यकीन नहीं है कि इसे और कैसे सेट किया जाए, और मुझे वर्तमान सिद्धांत की आवश्यकता नहीं लगती है। इसका परीक्षण किया और यह ठीक काम करता है।

अभी भी रुचि रखते हैं कि किसी के पास कोई बेहतर समाधान है या आप इस के साथ कोई समस्या देख सकते हैं।

+0

क्या आप GetUserNameAndPassword (actionContext, उपयोगकर्ता नाम से बाहर पासवर्ड) के लिए विधि निकाय साझा कर सकते हैं? –

+3

@ विजय बाल्कवाडे - यह कोड अब SimpleSecurity ओपन सोर्स प्रोजेक्ट का हिस्सा है। आप यहां GetUserNameAndPassword के लिए पूर्ण स्रोत कोड प्राप्त कर सकते हैं। https://simplesecurity.codeplex.com/SourceControl/latest#SimpleSecurity.Filters/BasicAuthorizeAttribute.cs –

+0

चूंकि कोडप्लेक्स जल्द ही बंद हो रहा है, इसलिए मैंने [GetUserNameAndPassword' को एक पेस्टबिन में कॉपी किया है] (https://pastebin.com/Yq86aNjL)। –

23

पहले से ही स्वीकृत उत्तर में जोड़ने के लिए: System.Web.Http.AuthorizeAttribute के लिए वर्तमान स्रोत कोड (aspnetwebstack.codeplex.com) की जांच करना, ऐसा लगता है कि प्रलेखन पुराना है। बेस OnAuthorization() बस निजी स्थिर SkipAuthorization() पर कॉल/चेक करता है (जो केवल AllowAnonymousAttribute को प्रमाणीकरण जांच को बाईपास करने के संदर्भ में उपयोग किया जाता है)। फिर, यदि छोड़ा नहीं गया है, OnAuthorization() सार्वजनिक IsAuthorized() पर कॉल करता है और यदि वह कॉल विफल हो जाता है, तो यह सुरक्षित वर्चुअल HandleUnauthorizedRequest() पर कॉल करता है। और कहा कि सभी यह है

public override void OnAuthorization(HttpActionContext actionContext) 
{ 
    if (actionContext == null) 
    { 
     throw Error.ArgumentNull("actionContext"); 
    } 

    if (SkipAuthorization(actionContext)) 
    { 
     return; 
    } 

    if (!IsAuthorized(actionContext)) 
    { 
     HandleUnauthorizedRequest(actionContext); 
    } 
} 

IsAuthorized() अंदर खोज रहे हैं कि जहां सिद्धांत भूमिकाओं और उपयोगकर्ताओं के खिलाफ चेक किया गया है है ...,। तो, IsAuthorized() को ओवरराइड करना जो आपके पास OnAuthorization() के बजाय ऊपर है, वहां जाने का तरीका होगा। फिर फिर, आपको अभी भी OnAuthorization() या HandleUnauthorizedRequest() ओवरराइड करना होगा, यह तय करने के लिए कि 401 बनाम 403 प्रतिक्रिया कब वापस करनी है।

1

केविन द्वारा बिल्कुल सही उत्तर में जोड़ने के लिए, मैं यह कहना चाहूंगा कि मैं फ्रेमवर्क (या अन्य उपभोक्ताओं) में डाउनस्ट्रीम कोड सुनिश्चित करने के लिए प्रतिक्रिया ऑब्जेक्ट के मौजूदा .NET फ्रेमवर्क पथ का लाभ उठाने के लिए थोड़ा सा संशोधित कर सकता हूं। कुछ अजीब idiosyncrasy द्वारा प्रतिकूल रूप से प्रभावित नहीं है कि भविष्यवाणी नहीं की जा सकती है।

विशेष रूप से इस इस कोड का उपयोग का मतलब है:

actionContext.Response = actionContext.ControllerContext.Request.CreateErrorResponse(HttpStatusCode.Unauthorized, REQUEST_NOT_AUTHORIZED); 
बजाय

:

actionContext.Response = new HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized); 

कहाँ REQUEST_NOT_AUTHORIZED है:

private const string REQUEST_NOT_AUTHORIZED = "Authorization has been denied for this request."; 

मैं खींच लिया कि string में SRResources.RequestNotAuthorized परिभाषा से। शुद्ध रूपरेखा।

ग्रेट उत्तर केविन! मैंने अपना ही तरीका उसी तरह कार्यान्वित किया क्योंकि बेस क्लास में OnAuthorization को निष्पादित करने का कोई मतलब नहीं था क्योंकि मैं एक HTTP शीर्षलेख की पुष्टि कर रहा था जो हमारे आवेदन के लिए अनुकूल था और वास्तव में प्रधानाचार्य को जांचना नहीं चाहता था क्योंकि कोई भी नहीं था।

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