لماذا يقوم AuthorizeAttribute بإعادة التوجيه إلى صفحة تسجيل الدخول لفشل المصادقة والترخيص؟

StackOverflow https://stackoverflow.com/questions/238437

سؤال

في 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 بدلاً من.حاليا هذا يعيد التوجيه إلى صفحة خطأ.

بالتأكيد لم يكن علي أن أفعل هذا؟

هل كانت مفيدة؟

المحلول

عندما تم تطويره لأول مرة ، كان 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);
        }
    }
}

نصائح أخرى

وهذا إضافة إلى وظيفة الدخول Page_Load الخاص بك:

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

وعندما يتم إعادة توجيه المستخدم هناك ولكن تم بالفعل تسجيل الدخول، فإنه يدل على الصفحة غير مصرح بها. إذا لم تقم بتسجيل أنهم في، فإنه يسقط من خلال ويظهر صفحة تسجيل الدخول.

واعتقدت دائما هذا لم معنى. إذا قمت بتسجيل الدخول ومحاولة ضرب صفحة تتطلب دورا لم يكن لديك، يمكنك الحصول على إرسالها إلى شاشة تسجيل الدخول يطلب منك تسجيل الدخول باستخدام مستخدم الذي لديه هذا الدور.

هل يمكن إضافة منطق إلى صفحة تسجيل الدخول التي بالتحقق مما إذا تم مصادقة المستخدم بالفعل. هل يمكن أن تضيف رسالة الودية التي يفسر لماذا لقد تم bumbed إلى هناك مرة أخرى.

للأسف، كنت تتعامل مع السلوك الافتراضي مصادقة النماذج ASP.NET. هناك حلا (لم أحاول ذلك) مناقشتها هنا:

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

و(انها ليست محددة لMVC)

وأعتقد أنه في معظم الحالات فإن الحل الأفضل هو لتقييد الوصول إلى الموارد غير مصرح بها قبل المستخدم في محاولة للوصول إلى هناك. عن طريق إزالة / شيب من الارتباط أو الزر الذي قد يستغرق تحقيقها في هذه الصفحة غير مصرح بها.

وعلى الأرجح سيكون من الجميل أن يكون لديك معلمة إضافية على سمة لتحديد مكان إعادة توجيه المستخدمين غير المصرح به. لكن في الوقت نفسه، ألقي نظرة على AuthorizeAttribute كشبكة أمان.

وجرب هذا في بلدكم في معالج Application_EndRequest ملف Global.ascx بك

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

إذا باستخدام الخاص بك aspnetcore 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;
            }
        }
    }
}

في حالتي كانت المشكلة "HTTP مواصفات تستخدم رمز الحالة 401 لكلا" غير مصرح بها "و" غير مصادقة "". كما قال ShadowChaser.

وهذا الحل يعمل بالنسبة لي:

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" });
}
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top