2009-06-10 14 views
70

मैं ASP.NET MVC में एक नियंत्रक कि मैं व्यवस्थापक भूमिका को आपने रोक लगा दी है:ASP.NET में अनधिकृत नियंत्रक रीडायरेक्ट किया जा रहा MVC

[Authorize(Roles = "Admin")] 
public class TestController : Controller 
{ 
    ... 

वाले किसी उपयोगकर्ता द्वारा व्यवस्थापक की भूमिका में नहीं है इस पर जाता है तो नियंत्रक उन्हें एक खाली स्क्रीन के साथ बधाई दी जाती है।

मैं क्या करना चाहता हूं उन्हें यह देखने के लिए पुनर्निर्देशित करता है कि "आपको इस संसाधन तक पहुंचने में सक्षम होने के लिए व्यवस्थापक भूमिका में होना चाहिए।"

ऐसा करने का एक तरीका है जिसे मैंने सोचा है कि IsUserInRole() पर प्रत्येक एक्शन विधि में चेक होना है और यदि भूमिका में नहीं है तो इस सूचनात्मक दृश्य को वापस कर दें। हालांकि, मुझे इसे प्रत्येक एक्शन में रखना होगा जो डीआरवाई प्रिंसिपल को तोड़ता है और यह सुनिश्चित करने के लिए स्पष्ट रूप से बोझिल है।

उत्तर

67

एक कस्टम प्राधिकरण AuthorizeAttribute के आधार पर विशेषता बनाएँ और जांच कैसे आप यह चाहते किया प्रदर्शन करने के लिए OnAuthorization ओवरराइड। आम तौर पर, अगर प्राधिकरण जांच विफल हो जाती है तो AuthorizeAttribute फ़िल्टर परिणाम को HttpUnauthorizedResult पर सेट कर देगा। आप इसे इसके बजाय ViewResult (आपके त्रुटि दृश्य के) पर सेट कर सकते हैं।

संपादित:

उदाहरण::

[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = false)] 
    public class MasterEventAuthorizationAttribute : AuthorizeAttribute 
    { 
     /// <summary> 
     /// The name of the master page or view to use when rendering the view on authorization failure. Default 
     /// is null, indicating to use the master page of the specified view. 
     /// </summary> 
     public virtual string MasterName { get; set; } 

     /// <summary> 
     /// The name of the view to render on authorization failure. Default is "Error". 
     /// </summary> 
     public virtual string ViewName { get; set; } 

     public MasterEventAuthorizationAttribute() 
      : base() 
     { 
      this.ViewName = "Error"; 
     } 

     protected void CacheValidateHandler(HttpContext context, object data, ref HttpValidationStatus validationStatus) 
     { 
      validationStatus = OnCacheAuthorization(new HttpContextWrapper(context)); 
     } 

     public override void OnAuthorization(AuthorizationContext filterContext) 
     { 
      if (filterContext == null) 
      { 
       throw new ArgumentNullException("filterContext"); 
      } 

      if (AuthorizeCore(filterContext.HttpContext)) 
      { 
       SetCachePolicy(filterContext); 
      } 
      else if (!filterContext.HttpContext.User.Identity.IsAuthenticated) 
      { 
       // auth failed, redirect to login page 
       filterContext.Result = new HttpUnauthorizedResult(); 
      } 
      else if (filterContext.HttpContext.User.IsInRole("SuperUser")) 
      { 
       // is authenticated and is in the SuperUser role 
       SetCachePolicy(filterContext); 
      } 
      else 
      { 
       ViewDataDictionary viewData = new ViewDataDictionary(); 
       viewData.Add("Message", "You do not have sufficient privileges for this operation."); 
       filterContext.Result = new ViewResult { MasterName = this.MasterName, ViewName = this.ViewName, ViewData = viewData }; 
      } 

     } 

     protected void SetCachePolicy(AuthorizationContext filterContext) 
     { 
      // ** IMPORTANT ** 
      // Since we're performing authorization at the action level, the authorization code runs 
      // after the output caching module. In the worst case this could allow an authorized user 
      // to cause the page to be cached, then an unauthorized user would later be served the 
      // cached page. We work around this by telling proxies not to cache the sensitive page, 
      // then we hook our custom authorization code into the caching mechanism so that we have 
      // the final say on whether a page should be served from the cache. 
      HttpCachePolicyBase cachePolicy = filterContext.HttpContext.Response.Cache; 
      cachePolicy.SetProxyMaxAge(new TimeSpan(0)); 
      cachePolicy.AddValidationCallback(CacheValidateHandler, null /* data */); 
     } 


    } 
+1

करना चाहिए मुझे नहीं लगता कि एक लिंक है जिसे मैं इसे नीचे ले जाने के कारण थोड़ा सा आसान कर सकता हूं? – Maslow

+1

क्या स्पष्ट नहीं है? यह पहली बार प्राधिकृतकोर का उपयोग यह जांचने के लिए करता है कि उपयोगकर्ता अधिकृत है या अनुमति की भूमिका में है या नहीं। यदि नहीं, तो यदि उपयोगकर्ता प्रमाणीकृत नहीं है तो यह फ़िल्टर के संदर्भ पर परिणाम सेट करके अनधिकृत प्रतिक्रिया देता है। यदि यह प्रमाणित है, तो यह जांचता है कि क्या यह "सुपर यूज़र" की अतिरिक्त भूमिका में है (एक डिफ़ॉल्ट भूमिका, विशेषता में निर्दिष्ट नहीं है)। यदि नहीं, तो यह इंगित करता है कि अधिकृत होने पर, उपयोगकर्ता कार्रवाई के लिए वैध भूमिका में नहीं है। जब उपयोगकर्ता अधिकृत होता है और वैध भूमिका (या सुपरयूसर) में, यह डाउनस्ट्रीम कैशिंग – tvanfosson

+0

को रोकने के लिए कैश नीति सेट करता है, तो मुझे यहां एक बेहतर उत्तर मिला: http://stackoverflow.com/questions/1498727/asp-net-mvc- कैसे-टू-शो-अनधिकृत-त्रुटि-ऑन-लॉगिन-पेज – bluee

1

आपको अपना स्वयं का प्राधिकरण-फ़िल्टर विशेषता बनाना चाहिए।

यहाँ मेरा अध्ययन करने के लिए है,)

Public Class RequiresRoleAttribute : Inherits ActionFilterAttribute 
    Private _role As String 

    Public Property Role() As String 
     Get 
      Return Me._role 
     End Get 
     Set(ByVal value As String) 
      Me._role = value 
     End Set 
    End Property 

    Public Overrides Sub OnActionExecuting(ByVal filterContext As System.Web.Mvc.ActionExecutingContext) 
     If Not String.IsNullOrEmpty(Me.Role) Then 
      If Not filterContext.HttpContext.User.Identity.IsAuthenticated Then 
       Dim redirectOnSuccess As String = filterContext.HttpContext.Request.Url.AbsolutePath 
       Dim redirectUrl As String = String.Format("?ReturnUrl={0}", redirectOnSuccess) 
       Dim loginUrl As String = FormsAuthentication.LoginUrl + redirectUrl 

       filterContext.HttpContext.Response.Redirect(loginUrl, True) 
      Else 
       Dim hasAccess As Boolean = filterContext.HttpContext.User.IsInRole(Me.Role) 
       If Not hasAccess Then 
        Throw New UnauthorizedAccessException("You don't have access to this page. Only " & Me.Role & " can view this page.") 
       End If 
      End If 
     Else 
      Throw New InvalidOperationException("No Role Specified") 
     End If 

    End Sub 
End Class 
+0

इस रीडायरेक्ट करने के लिए प्रकट होता है, लेकिन यह भी मूल कार्रवाई पद्धति पर संपूर्णता पर चलती प्रतीत प्रथम। –

+0

रीडायरेक्ट करने के बजाए, आपको 'filterContext.Result = new RedirectResult (loginUrl) ' –

5

मैं था मैं ब्लॉग पोस्ट की एक जोड़ी है कि और अधिक विस्तार में जाने की है वही मुद्दा। एमवीसी कोड को समझने के बजाय, मैंने काम करने के लिए एक सस्ते हैक का चयन किया। मेरी Global.asax वर्ग में:

member x.Application_EndRequest() = 
    if x.Response.StatusCode = 401 then 
     let redir = "?redirectUrl=" + Uri.EscapeDataString x.Request.Url.PathAndQuery 
     if x.Request.Url.LocalPath.ToLowerInvariant().Contains("admin") then 
      x.Response.Redirect("/Login/Admin/" + redir) 
     else 
      x.Response.Redirect("/Login/Login/" + redir) 
9

"tvanfosson" द्वारा कोड मुझे दे रहा था "बाल अनुरोध को क्रियान्वित करने में त्रुटि" .. मैं इस तरह OnAuthorization बदल गए हैं:

public override void OnAuthorization(AuthorizationContext filterContext) 
    { 
     base.OnAuthorization(filterContext); 

     if (!_isAuthorized) 
     { 
      filterContext.Result = new HttpUnauthorizedResult(); 
     } 
     else if (filterContext.HttpContext.User.IsInRole("Administrator") || filterContext.HttpContext.User.IsInRole("User") || filterContext.HttpContext.User.IsInRole("Manager")) 
     { 
      // is authenticated and is in one of the roles 
      SetCachePolicy(filterContext); 
     } 
     else 
     { 
      filterContext.Controller.TempData.Add("RedirectReason", "You are not authorized to access this page."); 
      filterContext.Result = new RedirectResult("~/Error"); 
     } 
    } 

यह अच्छी तरह से काम करता है और मैं त्रुटि पृष्ठ पर TempData दिखाता हूं। कोड स्निपेट के लिए "tvanfosson" के लिए धन्यवाद। मैं विंडोज प्रमाणीकरण का उपयोग कर रहा हूं और _is प्राधिकृत कुछ भी नहीं है लेकिन HttpContext.User.Identity.Is प्रमाणीकृत ...

+0

क्या यह यूआरएल पर एक 401 लौटाता है जिसे उपयोगकर्ता को अनुमति नहीं है, हालांकि? – DevDave

22

आप अपने कस्टम AuthorizeAttribute

इस तरह

अंदर overridable HandleUnauthorizedRequest के साथ काम कर सकते हैं:

protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext) 
{ 
    // Returns HTTP 401 by default - see HttpUnauthorizedResult.cs. 
    filterContext.Result = new RedirectToRouteResult(
    new RouteValueDictionary 
    { 
     { "action", "YourActionName" }, 
     { "controller", "YourControllerName" }, 
     { "parameterName", "YourParameterValue" } 
    }); 
} 

तुम भी कुछ इस तरह कर सकते हैं:

private class RedirectController : Controller 
{ 
    public ActionResult RedirectToSomewhere() 
    { 
     return RedirectToAction("Action", "Controller"); 
    } 
} 

अब आप उस में उपयोग कर सकते हैं आपकी HandleUnauthorizedRequest इस तरह से विधि:

filterContext.Result = (new RedirectController()).RedirectToSomewhere(); 
2

इस समस्या ने मुझे कुछ दिनों के लिए परेशान कर दिया है, इसलिए जवाब देने के लिए उत्तरदायी रूप से tvanfosson के उत्तर के साथ काम करता है, मैंने सोचा कि उत्तर के मुख्य भाग पर जोर देना और कुछ संबंधित पकड़ को संबोधित करना उचित होगा। मैं एक आधार नियंत्रक से विरासत है, इसलिए प्रत्येक नियंत्रक है कि यह से विरासत में मैं OnAuthorize ओवरराइड मेरे मामले में

filterContext.Result = new HttpUnauthorizedResult(); 

:

कोर जवाब यह, मिठाई और सरल है

protected override void OnAuthorization(AuthorizationContext filterContext) 
{ 
    base.OnAuthorization(filterContext); 
    YourAuth(filterContext); // do your own authorization logic here 
} 

समस्या यह थी कि 'योरऑथ' में, मैंने दो चीजों की कोशिश की जो मैंने सोचा कि न केवल काम करेगा, बल्कि तुरंत अनुरोध को समाप्त कर देगा। खैर, यह नहीं है कि यह कैसे काम करता है। तो सबसे पहले, दो चीजें हैं जो काम नहीं करते हैं, अप्रत्याशित रूप से:

filterContext.RequestContext.HttpContext.Response.Redirect("/Login"); // doesn't work! 
FormsAuthentication.RedirectToLoginPage(); // doesn't work! 

इतना ही नहीं उन से काम नहीं करते हैं, वे या तो अनुरोध न करना पड़े। जिसका अर्थ है निम्नलिखित:

if (!success) { 
    filterContext.Result = new HttpUnauthorizedResult(); 
} 
DoMoreStuffNowThatYouThinkYourAuthorized(); 

ठीक है, ऊपर दिए गए सही उत्तर के साथ भी, तर्क का प्रवाह अभी भी जारी है! आप अभी भी DoMoreStuff ... ऑनऑनराइज के भीतर हिट करेंगे। तो इसे ध्यान में रखें (DoMore ... इसलिए किसी और में होना चाहिए)।

लेकिन सही उत्तर के साथ, जबकि तर्क का ऑनअधिकृत प्रवाह अंत तक जारी रहता है, उसके बाद आप वास्तव में जो भी उम्मीद करते हैं उसे प्राप्त करते हैं: आपके लॉगिन पृष्ठ पर रीडायरेक्ट (यदि आपके पास अपने वेबकॉन्ग में फ़ॉर्म्स ऑथ में एक सेट है) ।

लेकिन अप्रत्याशित रूप से, 1) Response.Redirect ("/ लॉग इन") काम नहीं करता है: कार्रवाई पद्धति अभी भी बुलाया जाता है, और 2) FormsAuthentication.RedirectToLoginPage(); वही काम करता है: एक्शन विधि अभी भी कॉल हो जाती है!

जो मेरे लिए पूरी तरह से गलत लगता है, विशेष रूप से उत्तरार्द्ध के साथ: कौन सोचा होगा कि फॉर्म प्रमाणीकरण। रीडायरेक्ट टोलोगिनपेज अनुरोध समाप्त नहीं करता है, या फ़िल्टरकॉन्टेक्स्ट.Result = new HttpUnuthorizedResult() के समकक्ष समकक्ष करता है?

1

इसे एक टिप्पणी के रूप में छोड़ दिया होगा, लेकिन मुझे और अधिक प्रतिनिधि की आवश्यकता है, वैसे भी मैं निकोलस पीटरसन को उल्लेख करना चाहता हूं कि शायद रीडायरेक्ट कॉल के दूसरे तर्क को पारित करने के लिए यह कहने के लिए कि प्रतिक्रिया समाप्त हो गई होगी। इसे संभालने का सबसे बढ़िया तरीका नहीं है लेकिन यह वास्तव में काम करता है।

तो

filterContext.RequestContext.HttpContext.Response.Redirect("/Login", true); 
बजाय

filterContext.RequestContext.HttpContext.Response.Redirect("/Login); 

तो आप इस अपने नियंत्रक में होगा: जब आप दृश्य स्टूडियो से चलाने

protected override void OnAuthorization(AuthorizationContext filterContext) 
{ 
     if(!User.IsInRole("Admin") 
     { 
      base.OnAuthorization(filterContext); 
      filterContext.RequestContext.HttpContext.Response.Redirect("/Login", true); 
     } 
} 
1

शायद आप एक रिक्त पृष्ठ मिल विंडोज प्रमाणीकरण (previous topic) का उपयोग कर विकास सर्वर के तहत।

आप system.webServer तहत IIS करने के लिए आप विशिष्ट स्थिति कोड के लिए कस्टम एरर पृष्ठ कॉन्फ़िगर कर सकते हैं, इस मामले में 401 जोड़ें httpErrors तैनात हैं:

<httpErrors> 
    <remove statusCode="401" /> 
    <error statusCode="401" path="/yourapp/error/unauthorized" responseMode="Redirect" /> 
</httpErrors> 

फिर ErrorController.Unauthorized विधि और कस्टम दृश्य इसी पैदा करते हैं।

-1

अपने Startup.Auth.cs में दायर इस पंक्ति जोड़ें:

LoginPath = new PathString("/Account/Login"), 

उदाहरण:

// Enable the application to use a cookie to store information for the signed in user 
// and to use a cookie to temporarily store information about a user logging in with a third party login provider 
// Configure the sign in cookie 
app.UseCookieAuthentication(new CookieAuthenticationOptions 
{ 
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie, 
    LoginPath = new PathString("/Account/Login"), 
    Provider = new CookieAuthenticationProvider 
    { 
     // Enables the application to validate the security stamp when the user logs in. 
     // This is a security feature which is used when you change a password or add an external login to your account. 
     OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
     validateInterval: TimeSpan.FromMinutes(30), 
     regenerateIdentity: (manager, user) => user.GenerateUserIdentityAsync(manager)) 
    } 
}); 
संबंधित मुद्दे