2010-05-15 20 views
64

मेरे पास एक ऐसा एप्लिकेशन है जो एएसपी.नेट फॉर्म प्रमाणीकरण का उपयोग करता है। अधिकांश भाग के लिए, यह बहुत अच्छा काम कर रहा है, लेकिन मैं एक .ashx फ़ाइल के माध्यम से एक साधारण एपीआई के लिए समर्थन जोड़ने की कोशिश कर रहा हूं। मैं एएसएक्स फ़ाइल को वैकल्पिक प्रमाणीकरण चाहता हूं (यानी यदि आप प्रमाणीकरण शीर्षलेख की आपूर्ति नहीं करते हैं, तो यह अनामित रूप से काम करता है)। लेकिन, आप जो करते हैं उसके आधार पर, मैं कुछ शर्तों के तहत प्रमाणीकरण की आवश्यकता चाहता हूं।प्रपत्र प्रमाणीकरण: लॉगिन पृष्ठ पर रीडायरेक्ट अक्षम करें

मैंने सोचा कि यदि आवश्यक प्रमाणीकरण की आपूर्ति नहीं की गई है तो स्थिति कोड 401 के साथ प्रतिक्रिया देने का यह एक साधारण मामला होगा, लेकिन ऐसा लगता है कि प्रपत्र प्रमाणीकरण मॉड्यूल उसमें अवरुद्ध है और इसके बजाय लॉगिन पृष्ठ पर रीडायरेक्ट का जवाब दे रहा है। , ग्राहक पर एक 401 त्रुटि कोड हो रही के बजाय फिर

public void ProcessRequest(HttpContext context) 
{ 
    Response.StatusCode = 401; 
    Response.StatusDescription = "Authentication required"; 
} 

की तरह मैं उम्मीद, मैं वास्तव में एक 302 लॉगिन पृष्ठ पर पुनर्निर्देशित हो रही है: क्या मेरा मतलब है, मेरी ProcessRequest विधि इस तरह दिखता है, तो है ।

नोर्नल HTTP ट्रैफ़िक के लिए, मैं देख सकता हूं कि यह कैसे उपयोगी होगा, लेकिन मेरे एपीआई पेज के लिए, मैं 401 को अनमोडिफाइड के माध्यम से जाना चाहता हूं ताकि क्लाइंट-साइड कॉलर प्रोग्रामेटिक रूप से इसका जवाब दे सके।

क्या ऐसा करने का कोई तरीका है?

उत्तर

63

एएसपी.NET 4.5 ने बूलियन HttpResponse.SuppressFormsAuthenticationRedirect संपत्ति को जोड़ा।

public void ProcessRequest(HttpContext context) 
{ 
    Response.StatusCode = 401; 
    Response.StatusDescription = "Authentication required"; 
    Response.SuppressFormsAuthenticationRedirect = true; 
} 
+0

यह .NET 4.5 का उपयोग कर किसी के भी उत्तर है। बहुत बुरा मैंने सूची में इसे अभी तक नहीं पढ़ा और मुझे इसे अपने आप को अपूर्ण स्रोतों में ढूंढना पड़ा! –

+2

आप इसे अपने पूरे एप्लिकेशन में लागू करने के लिए Global.asax 'Application_EndRequest' ईवेंट में डाल सकते हैं। [उदाहरण के लिए।] (Http://stackoverflow.com/a/18519725/188246) –

+3

मैंने बड़ी सफलता के साथ Application_BeginRequest विधि में एक समान स्निपेट का उपयोग किया। अनुरोध AJAX है? तुरंत ध्वज सेट करें। –

-2

configuration\authentication में अपनी वेब.कॉन्फिग फ़ाइल के अंदर देखो। यदि उपशीर्षक loginUrl विशेषता के साथ है, तो इसे हटाएं और पुनः प्रयास करें।

+2

यह हटाकर कि यह यूआरएल बदल गया है, यह मेरे कस्टम एक के बजाय '/ login.aspx' पर रीडायरेक्ट करता है। मैं वैसे भी "सामान्य" पृष्ठों के लिए फॉर्म प्रमाणीकरण रखना चाहता हूं, सिर्फ इस के लिए .ashx फ़ाइल मैं इसे बदलना चाहता था। –

33

कुछ जांच के बाद, ऐसा लगता है कि FormsAuthenticationModuleHttpApplicationContext.EndRequest ईवेंट के लिए हैंडलर जोड़ता है। इसके हैंडलर में, यह 401 स्टेटस कोड की जांच करता है और मूल रूप से Response.Redirect(loginUrl) करता है। जहां तक ​​मैं कह सकता हूं, FormsAuthenticationModule का उपयोग करना चाहते हैं, तो इस व्यवहार को ओवरराइड करने का कोई तरीका नहीं है।

तरह से मैं यह चारों ओर हो रही है समाप्त हो गया तो जैसे web.config में FormsAuthenticationModule को अक्षम करके किया गया था:

<authentication mode="None" /> 

और फिर लागू करने Application_AuthenticateEvent अपने आप:

void Application_AuthenticateRequest(object sender, EventArgs e) 
{ 
    if (Context.User == null) 
    { 
     var oldTicket = ExtractTicketFromCookie(Context, FormsAuthentication.FormsCookieName); 
     if (oldTicket != null && !oldTicket.Expired) 
     { 
      var ticket = oldTicket; 
      if (FormsAuthentication.SlidingExpiration) 
      { 
       ticket = FormsAuthentication.RenewTicketIfOld(oldTicket); 
       if (ticket == null) 
        return; 
      } 

      Context.User = new GenericPrincipal(new FormsIdentity(ticket), new string[0]); 
      if (ticket != oldTicket) 
      { 
       // update the cookie since we've refreshed the ticket 
       string cookieValue = FormsAuthentication.Encrypt(ticket); 
       var cookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName] ?? 
          new HttpCookie(FormsAuthentication.FormsCookieName, cookieValue) { Path = ticket.CookiePath }; 

       if (ticket.IsPersistent) 
        cookie.Expires = ticket.Expiration; 
       cookie.Value = cookieValue; 
       cookie.Secure = FormsAuthentication.RequireSSL; 
       cookie.HttpOnly = true; 
       if (FormsAuthentication.CookieDomain != null) 
        cookie.Domain = FormsAuthentication.CookieDomain; 
       Context.Response.Cookies.Remove(cookie.Name); 
       Context.Response.Cookies.Add(cookie); 
      } 
     } 
    } 
} 

private static FormsAuthenticationTicket ExtractTicketFromCookie(HttpContext context, string name) 
{ 
    FormsAuthenticationTicket ticket = null; 
    string encryptedTicket = null; 

    var cookie = context.Request.Cookies[name]; 
    if (cookie != null) 
    { 
     encryptedTicket = cookie.Value; 
    } 

    if (!string.IsNullOrEmpty(encryptedTicket)) 
    { 
     try 
     { 
      ticket = FormsAuthentication.Decrypt(encryptedTicket); 
     } 
     catch 
     { 
      context.Request.Cookies.Remove(name); 
     } 

     if (ticket != null && !ticket.Expired) 
     { 
      return ticket; 
     } 

     // if the ticket is expired then remove it 
     context.Request.Cookies.Remove(name); 
     return null; 
    } 
} 

यह वास्तव में थोड़ा अधिक है इससे जटिल, लेकिन मुझे मूल रूप से परावर्तक में FormsAuthenticationModule के कार्यान्वयन को देखकर कोड मिला। मेरा कार्यान्वयन अंतर्निहित FormsAuthenticationModule से अलग है, यदि आप 401 के साथ प्रतिक्रिया देते हैं तो यह कुछ भी नहीं करता है - लॉगिन पृष्ठ पर रीडायरेक्ट नहीं करता है। मुझे लगता है कि अगर यह कभी भी एक आवश्यकता बन जाता है, तो मैं ऑटो-रीडायरेक्ट या कुछ अक्षम करने के लिए संदर्भ में एक आइटम डाल सकता हूं।

+1

यह एएसपी.नेट एमवीसी में भी बहुत अच्छा काम करता है। –

+2

नोट: [zacharydl द्वारा उत्तर] (http://stackoverflow.com/a/16846041/241462) ऊपर एएसपी.NET 4.5+ –

11

मुझे यकीन नहीं है कि यह सभी के लिए काम करेगा, लेकिन आईआईएस 7 में आप स्टेटस कोड और विवरण सेट करने के बाद Response.End() को कॉल कर सकते हैं। इस तरह, वह # & $^# @ *! फॉर्म प्रमाणीकरण मॉड्यूल एक रीडायरेक्ट नहीं करेगा।

public void ProcessRequest(HttpContext context) { 
    Response.StatusCode = 401; 
    Response.StatusDescription = "Authentication required"; 
    Response.End(); 
} 
+3

में जाने का तरीका है एक अच्छा जॉन! क्या यह हास्यास्पद नहीं है कि इसे पाने के लिए हमें कितना मुश्किल करना है?HttpContext में एक SkipAuthorization प्रॉपर्टी है, यह अच्छा होगा अगर इसमें SkipLoginRedirect भी था। या यदि फॉर्म प्रमाणीकरण निर्देशिकाओं द्वारा स्कॉप्ड और ओवरराइड किया जा सकता है। –

+0

जब मैं इसे आज़मा रहा था, तो मैं आईआईएस 6 पर था और मुझे लगता है कि यह आईआईएस 7 बनाम आईआईएस 6 (यानी आईआईएस 6, 'Response.End() में सिर्फ थोड़ा सा काम करता है,' थ्रेडएबॉर्ट एक्सेप्शन 'जो फॉर्म प्रमाणीकरण मॉड्यूल पकड़ रहा था - जिसका अर्थ है कि यह अभी भी मेरे लिए तर्क रीडायरेक्ट किया है)। –

+0

ग्रेट यह काम किया! –

4

क्या तुम बाहर मिल गया है 401 में अवरोध डालने और एक रीडायरेक्ट कर प्रमाणन रूपों के बारे में सही है, लेकिन हम यह भी कहा कि कि उल्टा करने के लिए कर सकते हैं।

मूल रूप से आपको जो चाहिए वह 302 को लॉगिन पृष्ठ पर रीडायरेक्ट करने और इसे 401 पर वापस करने के लिए एक HTTP मॉड्यूल है।ऐसा करने पर

कदम here

दिए गए लिंक एक WCF सेवा के बारे में है से समझाया गया है, लेकिन यह सभी रूपों प्रमाणन स्थितियों में एक ही है।

उपर्युक्त लिंक में समझाया गया है कि आपको http शीर्षलेखों को भी साफ़ करने की आवश्यकता है, लेकिन यदि मूल प्रतिक्रिया (यानी अवरोध से पहले) में कोई कुकी शामिल है तो कुकी हेडर को प्रतिक्रिया में वापस रखना याद रखें।

+0

हम्म, हाँ, यह एक दिलचस्प विचार है! बेशक, मुझे पहले से ही एक समाधान मिला है जो मेरे लिए काम करता है, लेकिन मुझे यकीन है कि किसी और को यह एक बेहतर समाधान मिल सकता है। धन्यवाद! –

+0

ऐसा लगता है कि एक हैक की तरह ही अजीब साइड इफेक्ट्स होने की संभावना है! –

5

मुझे नहीं पता कि Response.End() आपके लिए कैसे काम करता है। मैंने इसे बिना किसी खुशी के करने की कोशिश की, फिर Response.End() के लिए एमएसडीएन को देखा: 'पृष्ठ के निष्पादन को रोकता है, और EndRequest ईवेंट उठाता है'।

क्या इसके लायक है के लिए मेरी हैक किया गया था:

_response.StatusCode = 401; 
_context.Items["401Override"] = true; 
_response.End(); 

फिर Global.cs में एक EndRequest हैंडलर (जो प्रमाणीकरण HttpModule के बाद कहा जाता हो जाएगा) जोड़ें:

protected void Application_EndRequest(object sender, EventArgs e) 
{ 
    if (HttpContext.Current.Items["401Override"] != null) 
    { 
     HttpContext.Current.Response.Clear(); 
     HttpContext.Current.Response.StatusCode = 401; 
    } 
} 
+0

पृष्ठ में, मैंने 'StatusCode = 418' का उपयोग किया और 'स्टेटस डिस्क्रिप्शन' में ओवरराइड टेक्स्ट जोड़ा। तब मैंने उन EndRequest ईवेंट में उन पर कब्जा कर लिया जहां मैंने आपके पास प्रतिक्रिया को रीसेट कर दिया था। अगर मैं पेज में स्टेटस कोड 401 का उपयोग करता हूं तो यह अभी भी रीडायरेक्ट हो जाता है। –

5

मुझे पता है कि पहले से ही है टिक के साथ एक जवाब लेकिन इसी तरह की समस्या को हल करने की कोशिश करते समय मुझे एक विकल्प के रूप में this (http://blog.inedo.com/2010/10/12/http-418-im-a-teapot-finally-a-%e2%80%9clegitimate%e2%80%9d-use/) मिला।

असल में आप अपने कोड में अपना HTTP स्टेटस कोड (उदा। 418) वापस कर देते हैं। मेरे मामले में एक डब्ल्यूसीएफ डेटा सेवा।

throw new DataServiceException(418, "401 Unauthorized"); 

तो कोड 401.

HttpApplication app = (HttpApplication)sender; 
if (app.Context.Response.StatusCode == 418) 
{ 
    app.Context.Response.StatusCode = 401; 
} 

ब्राउज़र/ग्राहक को वापस पुनर्लेखन के लिए सही सामग्री और स्थिति कोड प्राप्त होगा EndRequest घटना में इसे संभाल करने के लिए एक HTTP मॉड्यूल का उपयोग, यह बहुत अच्छा काम करता है मेरे लिए :)

यदि आप HTTP स्थिति कोड 418 के बारे में अधिक जानने में रुचि रखते हैं तो this question & answer देखें।

+0

बढ़िया! यह काम करता है जैसे मैं इसे काम करना चाहता हूं :) इसके बजाय समर्पित http मॉड्यूल जोड़कर मैंने "global.asax" ईवेंट EndRequest का उपयोग किया। इस घटना को "इनिट" विधि ओवरराइड करना संभव है –

+0

यह सिर्फ मेरे लिए आईआईएस 401 त्रुटि पृष्ठ लौटाता है – DevDave

+0

अपने खुद के स्टेटस कोड का उपयोग करके उल्लेख करने के लिए धन्यवाद: चूंकि मैं केवल एक ही पृष्ठ के लिए 401 लौटने की तलाश कर रहा था जिसने प्रमाणीकरण का परीक्षण किया AJAX कॉल, मैं अन्य सभी कामकाज से बचने के लिए उस पृष्ठ पर "असफल" 'Response.StatusCode' को 418 में बदलने में सक्षम था! आईआईएस 7 शिकायत करता है, लेकिन किसी भी इंसान को उस पृष्ठ पर जाने की आवश्यकता नहीं होगी। – Tukaro

2

यह एक ज्ञात मुद्दा है, और इसके लिए NuGet Package और/या source code उपलब्ध है।

0

आप अपने द्वारा दिखाए गए कोड में WWW-Authenticate शीर्षलेख सेट नहीं करते हैं, इसलिए ग्राहक प्रपत्र प्रमाणीकरण के बजाय HTTP प्रमाणीकरण नहीं कर सकता है। यदि ऐसा है, तो आपको 401 के बजाय 403 का उपयोग करना चाहिए, जिसे FormsAuthenticaitonModule द्वारा अवरुद्ध नहीं किया जाएगा।

7

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

protected void Application_BeginRequest() 
{ 
    HttpRequestBase request = new HttpRequestWrapper(Context.Request); 
    if (request.IsAjaxRequest()) 
    { 
     Context.Response.SuppressFormsAuthenticationRedirect = true; 
    } 
} 
संबंधित मुद्दे

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