प्रमाणीकरण और प्राधिकरण विफलताओं के लिए अधिकृत पेज लॉगिन पर पुनर्निर्देशित क्यों करता है?


265

ASP.NET MVC में, आप एक नियंत्रक विधि को चिह्नित कर सकते हैं AuthorizeAttribute इस तरह के :

[Authorize(Roles = "CanDeleteTags")]
public void Delete(string tagName)
{
    // ...
}

इसका मतलब यह है कि, यदि वर्तमान में लॉग-इन उपयोगकर्ता "CanDeleteTags" भूमिका में नहीं है, तो नियंत्रक विधि कभी नहीं कहा जाएगा।

दुर्भाग्य से, विफलताओं के लिए, AuthorizeAttribute रिटर्न HttpUnauthorizedResult, जो हमेशा HTTP स्थिति कोड 401 देता है। यह लॉगिन पृष्ठ पर पुनर्निर्देशन का कारण बनता है।

यदि उपयोगकर्ता लॉग इन नहीं है, तो यह सही समझ में आता है। हालांकि, अगर उपयोगकर्ता है पहले से लॉग इन है, लेकिन आवश्यक भूमिका में नहीं है, तो यह उन्हें लॉगिन पृष्ठ पर वापस भेजने के लिए भ्रमित कर रहा है।

ऐसा लगता है AuthorizeAttribute प्रमाणीकरण और प्राधिकरण को भ्रमित करता है।

ऐसा लगता है कि ASP.NET MVC में एक ओवरसाइट का एक सा है, या मैं कुछ याद कर रहा हूँ?

मुझे खाना बनाना है DemandRoleAttributeजो दोनों को अलग करता है। जब उपयोगकर्ता प्रमाणित नहीं होता है, तो वह HTTP 401 को लौटाता है, उन्हें लॉगिन पेज पर भेज देता है। जब उपयोगकर्ता लॉग इन होता है, लेकिन आवश्यक भूमिका में नहीं होता है, तो यह NotAuthorizedResultइसके बजाय बनाता है । वर्तमान में यह एक त्रुटि पृष्ठ पर पुनर्निर्देशित करता है।

निश्चित रूप से मुझे ऐसा करने की ज़रूरत नहीं थी?


10
बहुत बढ़िया सवाल है और मैं मानता हूँ, यह एक HTTP नहीं अधिकृत स्थिति फेंकना चाहिए।
प्योर.क्रोम

3
मुझे आपका समाधान पसंद है, रोजर। भले ही आप नहीं।
जॉन डेविस

मेरे लॉगिन पृष्ठ में उपयोगकर्ता को केवल रिटर्न यूआरएल के लिए पुनर्निर्देशित करने के लिए एक चेक है, यदि s / वह पहले से ही स्वनिर्धारित है। इसलिए मैं 302 रीडायरेक्ट का एक अनंत लूप बनाने में कामयाब रहा: डी वूट।
जुहान_

1
की जाँच करें इस
जोगी

रोजर, आपके समाधान पर अच्छा लेख - red-gate.com/simple-talk/dotnet/asp-net/… ऐसा लगता है कि आपका समाधान इस सफाई से करने का एकमात्र तरीका है
क्रेग

जवाबों:


305

जब यह पहली बार विकसित किया गया था, तो System.Web.Mvc.AuthorizeAttribute सही काम कर रहा था - HTTP विनिर्देश के पुराने संशोधनों ने "अनधिकृत" और "अनअथेंटेड" दोनों के लिए स्थिति कोड 401 का उपयोग किया।

मूल विनिर्देश से:

यदि अनुरोध में पहले से ही प्राधिकरण क्रेडेंशियल शामिल हैं, तो 401 प्रतिक्रिया इंगित करती है कि प्रमाणीकरण उन क्रेडेंशियल्स के लिए मना कर दिया गया है।

वास्तव में, आप भ्रम को वहीं देख सकते हैं - यह "प्रमाणीकरण" शब्द का उपयोग करता है जब इसका अर्थ "प्रमाणीकरण" होता है। हालांकि, हर रोज़ अभ्यास में, यह 403 को वापस करने के लिए अधिक समझ में आता है जब उपयोगकर्ता को प्रमाणित किया जाता है लेकिन अधिकृत नहीं है। यह संभावना नहीं है कि उपयोगकर्ता के पास क्रेडेंशियल्स का दूसरा सेट होगा जो उन्हें एक्सेस प्रदान करेगा - खराब उपयोगकर्ता अनुभव।

अधिकांश ऑपरेटिंग सिस्टम पर विचार करें - जब आप किसी ऐसी फ़ाइल को पढ़ने का प्रयास करते हैं जिसकी आपको अनुमति नहीं है, तो आपको लॉगिन स्क्रीन नहीं दिखाई जाती है!

शुक्र है, अस्पष्टता को दूर करने के लिए HTTP विनिर्देशों (जून 2014) को अपडेट किया गया था।

"हाइपर टेक्स्ट ट्रांसपोर्ट प्रोटोकॉल (HTTP / 1.1): ऑथेंटिकेशन" (RFC 7235) से:

401 (अनधिकृत) स्थिति कोड इंगित करता है कि अनुरोध लागू नहीं किया गया है क्योंकि इसमें लक्ष्य संसाधन के लिए वैध प्रमाणीकरण क्रेडेंशियल्स का अभाव है।

"हाइपरटेक्स्ट ट्रांसफर प्रोटोकॉल (HTTP / 1.1): शब्दार्थ और सामग्री" (RFC 7231) से:

403 (निषिद्ध) स्थिति कोड इंगित करता है कि सर्वर अनुरोध को समझ गया है लेकिन इसे अधिकृत करने से इनकार करता है।

दिलचस्प बात यह है कि ASP.NET MVC 1 को उस समय जारी किया गया था जब AuthorizeAttribute का व्यवहार सही था। अब, व्यवहार गलत है - HTTP / 1.1 विनिर्देश तय किया गया था।

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

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
public class AuthorizeAttribute : System.Web.Mvc.AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(System.Web.Mvc.AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Request.IsAuthenticated)
        {
            filterContext.Result = new System.Web.Mvc.HttpStatusCodeResult((int)System.Net.HttpStatusCode.Forbidden);
        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }
}

52
+1 बहुत अच्छा दृष्टिकोण। एक छोटा सुझाव: चेक करने के बजाय filterContext.HttpContext.User.Identity.IsAuthenticated, आप बस चेक कर सकते हैं filterContext.HttpContext.Request.IsAuthenticated, जो कि बिल्ट इन चेक के साथ आता है। देखें stackoverflow.com/questions/1379566/…
डैनियल लिउजी

> आप अपनी वेबसाइट के डिफॉल्ट नेमस्पेस में एक ही नाम (AuthorizeAttribute) के साथ एक नई विशेषता बना सकते हैं तो कंपाइलर MVC के मानक एक के बजाय इसे स्वचालित रूप से उठाएगा। यह एक त्रुटि के रूप में होता है: प्रकार या नाम स्थान 'प्राधिकृत' नहीं पाया जा सकता है (क्या आप किसी निर्देश को असेंबली संदर्भ याद कर रहे हैं?) दोनों System.Web.Mvc का उपयोग कर रहे हैं; और मेरे कस्टम प्राधिकारी के लिए नेमस्पेस नाम के वर्ग को नियंत्रक में संदर्भित किया जाता है। इसे हल करने के लिए मुझे [MyNamepace.Authorize]
तूफ़ान

2
@DePeter कल्पना कभी भी रीडायरेक्ट के बारे में कुछ नहीं कहता है, इसलिए रीडायरेक्ट एक बेहतर समाधान क्यों है? यह अकेले इसे हल करने के लिए हैक के बिना ajax अनुरोधों को मारता है।
एडम टिलिपर -

1
यह एमएस कनेक्ट पर लॉग इन किया जाना चाहिए क्योंकि यह स्पष्ट रूप से एक व्यवहार बग है। धन्यवाद।
टोनी वॉल

BTW, हम प्रवेश पृष्ठ पर पुनर्निर्देशित क्यों हैं ? सिर्फ एक ही अनुरोध के भीतर एक 401 कोड और लॉगिन पेज को सीधे आउटपुट क्यों नहीं किया जाता है?
सैंडरॉक

25

इसे अपने लॉगिन Page_Load फ़ंक्शन में जोड़ें:

// User was redirected here because of authorization section
if (User.Identity != null && User.Identity.IsAuthenticated)
    Response.Redirect("Unauthorized.aspx");

जब उपयोगकर्ता को पुनर्निर्देशित किया जाता है, लेकिन पहले से लॉग इन है, तो यह अनधिकृत पेज दिखाता है। यदि वे लॉग इन नहीं हैं, तो यह लॉगिन पेज के माध्यम से गिरता है और दिखाता है।


18
Page_Load एक वेबफॉर्म मोजो है
चांस

2
@Chance - फिर उस नियंत्रक के लिए डिफ़ॉल्ट एक्शनमेथोड में करें जिसे कॉल किया जाता है जहां कॉल करने के लिए फॉर्म सेटअप चालू किया गया है।
प्योर.क्रोम

यह वास्तव में वास्तव में अच्छा काम करता है हालांकि एमवीसी के लिए यह कुछ ऐसा होना चाहिए if (User.Identity != null && User.Identity.IsAuthenticated) return RedirectToRoute("Unauthorized");जहां अनधिकृत एक परिभाषित मार्ग नाम है।
मूसा मचुआ

तो आप एक संसाधन पूछते हैं, आप एक लॉगिन पृष्ठ पर पुनर्निर्देशित हो जाते हैं और आप फिर से 403 पृष्ठ पर पुनर्निर्देशित हो जाते हैं? मुझे बुरा लगता है। मैं एक भी अनुप्रेषित बिल्कुल भी बर्दाश्त नहीं कर सकता। IMO यह बात वैसे भी बहुत बुरी तरह से निर्मित है।
सैंडरॉक

3
आपके समाधान के अनुसार, यदि आप पहले ही लॉग इन कर चुके हैं और URL टाइप करके लॉगइन पेज पर जाएं ... यह आपको अनधिकृत पेज पर ले जाएगा। जो सही नहीं है।
राजशेखर रेड्डी

4

मैंने हमेशा सोचा कि यह समझ में आया। यदि आप लॉग इन हैं और आप एक ऐसे पेज को हिट करने की कोशिश करते हैं, जिसके लिए आपको एक भूमिका की आवश्यकता होती है, तो आपको लॉगिन स्क्रीन पर भेज दिया जाता है, जिसमें आपको उस उपयोगकर्ता के साथ लॉग इन करने के लिए कहा जाता है, जिसकी भूमिका है।

आप लॉगिन पृष्ठ पर तर्क जोड़ सकते हैं जो यह देखने के लिए जांचता है कि उपयोगकर्ता पहले से ही प्रमाणित है या नहीं। आप एक मैत्रीपूर्ण संदेश जोड़ सकते हैं जो बताता है कि क्यों उन्हें फिर से वहाँ वापस भेज दिया गया है।


4
यह मेरी भावना है कि ज्यादातर लोग किसी दिए गए वेब ऐप के लिए एक से अधिक पहचान नहीं रखते हैं। यदि वे करते हैं, तो वे सोचने के लिए पर्याप्त स्मार्ट हैं "मेरी वर्तमान आईडी में मोजो नहीं है, मैं दूसरे के रूप में वापस लॉग इन करूंगा"।
रोजर लिप्सकॉम्ब

यद्यपि लॉगिन पृष्ठ पर कुछ प्रदर्शित करने के बारे में आपका अन्य बिंदु एक अच्छा है। धन्यवाद।
रोजर लिप्सकॉम्ब

4

दुर्भाग्य से, आप ASP.NET के डिफ़ॉल्ट व्यवहार के साथ काम कर रहे हैं प्रमाणीकरण। यहाँ पर चर्चा की गई है (मैंने इसे आज़माया नहीं है) एक वर्कअराउंड है:

http://www.codeproject.com/KB/aspnet/Custon401Page.aspx

(यह MVC के लिए विशिष्ट नहीं है)

मुझे लगता है कि ज्यादातर मामलों में सबसे अच्छा समाधान उपयोगकर्ता को वहां पहुंचने से पहले अनधिकृत संसाधनों तक पहुंच को प्रतिबंधित करना है। लिंक या बटन को हटाकर / हटाकर जो इस अनधिकृत पृष्ठ पर ले जा सकते हैं।

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


मैं प्राधिकरण के आधार पर लिंक को हटाने की योजना बना रहा हूं (मैंने यहां कहीं उस पर एक प्रश्न देखा), इसलिए मैं बाद में एक HtmlHelper एक्सटेंशन विधि को कोड करूंगा।
रोजर लिप्सकॉम्ब

1
मुझे अभी भी उपयोगकर्ता को सीधे URL पर जाने से रोकना है, जो कि यह विशेषता है। मैं कस्टम 401 समाधान से बहुत खुश नहीं हूं (थोड़ा वैश्विक लगता है), इसलिए मैं RedirectToRouteResult पर अपने नोटऑउटहाइरिड मॉडलिंग की कोशिश करूंगा ...
रोजर लिप्सकॉम्ब

0

अपने Global.ascx फ़ाइल के Application_EndRequest हैंडलर में इसे आज़माएं

if (HttpContext.Current.Response.Status.StartsWith("302") && HttpContext.Current.Request.Url.ToString().Contains("/<restricted_path>/"))
{
    HttpContext.Current.Response.ClearContent();
    Response.Redirect("~/AccessDenied.aspx");
}

0

यदि आपकी एस्पेक्टकोर 2.0 का उपयोग कर रहे हैं, तो इसका उपयोग करें

using System;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Filters;

namespace Core
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true)]
    public class AuthorizeApiAttribute : Microsoft.AspNetCore.Authorization.AuthorizeAttribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            var user = context.HttpContext.User;

            if (!user.Identity.IsAuthenticated)
            {
                context.Result = new UnauthorizedResult();
                return;
            }
        }
    }
}

0

मेरे मामले में समस्या "अनधिकृत" और "अनधिकृत" "दोनों के लिए HTTP विनिर्देशन ने स्थिति कोड 401 का उपयोग किया था। जैसा छायाकार ने कहा।

यह समाधान मेरे लिए काम करता है:

if (User != null &&  User.Identity.IsAuthenticated && Response.StatusCode == 401)
{
    //Do whatever

    //In my case redirect to error page
    Response.RedirectToRoute("Default", new { controller = "Home", action = "ErrorUnauthorized" });
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.