سؤال

لديّ تطبيق Enterprise كبير يحتوي على كل من WebForms وصفحات MVC. يحتوي على إعدادات المصادقة والتفويض الحالية التي لا أريد تغييرها.

تم تكوين مصادقة WebForms في web.config:

 <authentication mode="Forms">
  <forms blah... blah... blah />
 </authentication>

 <authorization>
  <deny users="?" />
 </authorization>

قياسي إلى حد ما حتى الآن. لدي خدمة راحة جزء من هذا التطبيق الكبير وأريد استخدام مصادقة HTTP بدلاً من ذلك لهذه الخدمة.

لذلك ، عندما يحاول المستخدم الحصول على بيانات JSON من خدمة REST ، فإنه يعيد حالة HTTP 401 و WWW-Authenticate رأس. إذا استجابوا بـ HTTP تم تشكيله بشكل صحيح Authorization الرد يتيح لهم في.

المشكلة هي أن WebForms يتجاوز هذا بمستوى منخفض - إذا قمت بإرجاع 401 (غير مصرح به) ، فإنه يتجاوز ذلك مع 302 (إعادة توجيه إلى صفحة تسجيل الدخول). هذا جيد في المتصفح ولكن عديمة الفائدة لخدمة الراحة.

أرغب في إيقاف تشغيل إعداد المصادقة في الويب.

 <location path="rest">
  <system.web>
   <authentication mode="None" />
   <authorization><allow users="?" /></authorization>
  </system.web>
 </location>

ال تفويض بت تعمل بشكل جيد ، ولكن المصادقة خط (<authentication mode="None" />) يسبب استثناء:

إنه خطأ في استخدام قسم مسجل على أنه leftDefinition = 'machinetoapplication' وراء مستوى التطبيق.

أقوم بتكوين هذا على مستوى التطبيق - إنه في Web.Config - وهذا الخطأ مخصص لـ Web.Configs في المخرجين الفرعيين.

كيف يمكنني تجاوز المصادقة بحيث يستخدم كل ما تبقى من الموقع مصادقة WebForms وهذا الدليل واحد يستخدم لا شيء؟

هذا مشابه لسؤال آخر: 401 رمز الاستجابة لطلبات JSON مع ASP.NET MVC, ، لكنني لا أبحث عن نفس الحل - لا أريد فقط إزالة مصادقة WebForms وإضافة رمز مخصص جديد على مستوى العالم ، وهناك الكثير من المخاطر والعمل المعني. أريد تغيير الدليل الوحيد في التكوين.

تحديث

أرغب في إعداد تطبيق ويب واحد وأريد أن تستخدم جميع صفحات WebForms و MVC Views مصادقة WebForms. أريد دليلًا واحدًا لاستخدام مصادقة HTTP الأساسية.

لاحظ أنني أتحدث عن المصادقة ، وليس التفويض. أريد أن تأتي مكالمات REST مع اسم المستخدم وكلمة المرور في رأس HTTP ، وأريد أن تأتي صفحات WebForm & MVC مع ملف تعريف الارتباط المصادقة من .NET - في كلتا الحالتين يتم ترخيصه مقابل DB.

لا أرغب في إعادة كتابة مصادقة WebForms ولف ملفات تعريف الارتباط الخاصة بي - يبدو الأمر مثيرًا للسخرية هي الطريقة الوحيدة لإضافة خدمة REST المعتمدة من HTTP إلى تطبيق.

لا يمكنني إضافة تطبيق إضافي أو دليل افتراضي - يجب أن يكون تطبيقًا واحدًا.

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

المحلول 2

لقد عملت حول هذه الطريقة الفوضوية - عن طريق تخفيف مصادقة النماذج في Global.asax لجميع الصفحات الموجودة.

ما زلت لا أملك هذا العمل بالكامل ، لكنه يسير على هذا النحو:

protected void Application_BeginRequest(object sender, EventArgs e)
{
    // lots of existing web.config controls for which webforms folders can be accessed
    // read the config and skip checks for pages that authorise anon users by having
    // <allow users="?" /> as the top rule.

    // check local config
    var localAuthSection = ConfigurationManager.GetSection("system.web/authorization") as AuthorizationSection;

    // this assumes that the first rule will be <allow users="?" />
    var localRule = localAuthSection.Rules[0];
    if (localRule.Action == AuthorizationRuleAction.Allow &&
        localRule.Users.Contains("?"))
    {
        // then skip the rest
        return;
    }

    // get the web.config and check locations
    var conf = WebConfigurationManager.OpenWebConfiguration("~");
    foreach (ConfigurationLocation loc in conf.Locations)
    {
        // find whether we're in a location with overridden config
        if (this.Request.Path.StartsWith(loc.Path, StringComparison.OrdinalIgnoreCase) ||
            this.Request.Path.TrimStart('/').StartsWith(loc.Path, StringComparison.OrdinalIgnoreCase))
        {
            // get the location's config
            var locConf = loc.OpenConfiguration();
            var authSection = locConf.GetSection("system.web/authorization") as AuthorizationSection;
            if (authSection != null)
            {
                // this assumes that the first rule will be <allow users="?" />
                var rule = authSection.Rules[0];
                if (rule.Action == AuthorizationRuleAction.Allow &&
                    rule.Users.Contains("?"))
                {
                    // then skip the rest
                    return;
                }
            }
        }
    }

    var cookie = this.Request.Cookies[FormsAuthentication.FormsCookieName];
    if (cookie == null ||
        string.IsNullOrEmpty(cookie.Value))
    {
        // no or blank cookie
        FormsAuthentication.RedirectToLoginPage();
    }

    // decrypt the 
    var ticket = FormsAuthentication.Decrypt(cookie.Value);
    if (ticket == null ||
        ticket.Expired)
    {
        // invalid cookie
        FormsAuthentication.RedirectToLoginPage();
    }

    // renew ticket if needed
    var newTicket = ticket;
    if (FormsAuthentication.SlidingExpiration)
    {
        newTicket = FormsAuthentication.RenewTicketIfOld(ticket);
    }

    // set the user so that .IsAuthenticated becomes true
    // then the existing checks for user should work
    HttpContext.Current.User = new GenericPrincipal(new FormsIdentity(newTicket), newTicket.UserData.Split(','));

}

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

نصائح أخرى

إذا كان "REST" مجرد مجلد في جذرك ، فأنت هناك تقريبًا: قم بإزالة خط المصادقة أي

<location path="rest">
  <system.web>
      <authorization>
        <allow users="*" />
      </authorization>
  </system.web>
 </location>

بدلاً من ذلك ، يمكنك إضافة web.config إلى مجلد الراحة الخاص بك والحصول على هذا فقط:

<system.web>
     <authorization>
          <allow users="*" />
     </authorization>
</system.web>

الشيك هذه واحد.

لقد وجدت نفسي بنفس المشكلة الدقيقة ، أشارني المقال التالي في الاتجاه الصحيح: http://msdn.microsoft.com/en-us/library/aa479391.aspx

تقوم سيدتي بالضبط بما أنت عليه بعد ذلك ، على وجه التحديد ، يمكنك تكوين FormauthenticationDispositionModule لتكثيف مصادقة النماذج "الخداع" ، ومنعها من تغيير رمز الاستجابة من 401 إلى 302. يجب أن يؤدي ذلك إلى استلام عميل الراحة الخاص بك تحدي المصادقة الصحيح.

صفحة تنزيل سيدتي: http://www.riboof.com/projects/madam/

في حالتي ، يتم إجراء مكالمات REST إلى وحدات التحكم (هذا تطبيق يعتمد على MVC) في منطقة "API". تم تعيين تمييز سيدتي مع التكوين التالي:

<formsAuthenticationDisposition>
  <discriminators all="1">
    <discriminator type="Madam.Discriminator">
      <discriminator
          inputExpression="Request.Url"
          pattern="api\.*" type="Madam.RegexDiscriminator" />
    </discriminator>
  </discriminators>
</formsAuthenticationDisposition>

ثم كل ما عليك فعله هو إضافة وحدة Madam إلى الويب الخاص بك

<modules runAllManagedModulesForAllRequests="true">
  <remove name="WebDAVModule" /> <!-- allow PUT and DELETE methods -->
  <add name="FormsAuthenticationDisposition" type="Madam.FormsAuthenticationDispositionModule, Madam" />
</modules>

تذكر إضافة الأقسام الصالحة إلى الويب.

مع هذا الإعداد ، ستحصل أي طلبات على URL التي تبدأ بـ "API/" على استجابة 401 بدلاً من 301 التي تنتجها مصادقة النماذج.

تمكنت من الحصول على هذا العمل في مشروع سابق ، لكنه يتطلب استخدام وحدة HTTP لأداء المصادقة الأساسية المخصصة ، نظرًا لأن التحقق من صحة الحساب هو ضد قاعدة بيانات بدلاً من Windows.

قمت بإعداد الاختبار كما حددت مع تطبيق ويب واحد على جذر موقع الاختبار ، ومجلد يحتوي على خدمة REST. تم تكوين التكوين لتطبيق الجذر لإنكار كل الوصول:

<authentication mode="Forms">
  <forms loginUrl="Login.aspx" timeout="2880" />
</authentication>
<authorization>
  <deny users="?"/>
</authorization>

ثم اضطررت إلى إنشاء تطبيق لمجلد REST في IIS ، ووضع ملف web.config في مجلد REST. في هذا التكوين ، حددت ما يلي:

<authentication mode="None"/>
<authorization>
  <deny users="?"/>
</authorization>

اضطررت أيضًا إلى توصيل وحدة HTTP في الأماكن المناسبة داخل تكوين دليل REST. هذه الوحدة يجب انتقل إلى دليل بن تحت دليل الراحة. لقد استخدمت وحدة المصادقة الأساسية المخصصة لـ Dominick Baier ، ويقع هذا الرمز هنا. هذا الإصدار أكثر محددة من IIS 6 ، ولكن هناك إصدار لـ IIS 7 أيضًا codeplex, ، لكنني لم أختبر ذلك (تحذير: لا يحتوي إصدار IIS6 على نفس اسم التجميع ومساحة الاسم كإصدار IIS7.) أنا حقًا أحب وحدة Auth الأساسية هذه لأنه يتم توصيله مباشرة في نموذج عضوية ASP.NET.

كانت الخطوة الأخيرة هي التأكد من أنه تم السماح فقط للوصول المجهول بتطبيق الجذر وتطبيق REST داخل IIS.

لقد قمت بتضمين التكوينات الكاملة أدناه للاكتمال. كان تطبيق الاختبار مجرد تطبيق نموذج ويب ASP.NET تم إنشاؤه من VS 2010 ، وكان يستخدم ASPNETSQLProfileProvider لمزود العضوية ؛ هذا هو التكوين:

<?xml version="1.0"?>

<configuration>
  <connectionStrings>
    <add name="ApplicationServices"
      connectionString="data source=.\SQLEXPRESS;Integrated Security=SSPI;Database=sqlmembership;"
    providerName="System.Data.SqlClient" />
  </connectionStrings>

  <system.web>
    <compilation debug="true" targetFramework="4.0" />

    <authentication mode="Forms">
      <forms loginUrl="~/Account/Login.aspx" timeout="2880" />
    </authentication>

    <authorization>
      <deny users="?"/>
    </authorization>

    <membership>
      <providers>
        <clear/>
        <add name="AspNetSqlMembershipProvider" type="System.Web.Security.SqlMembershipProvider" connectionStringName="ApplicationServices"
          enablePasswordRetrieval="false" enablePasswordReset="true" requiresQuestionAndAnswer="false" requiresUniqueEmail="false"
          maxInvalidPasswordAttempts="5" minRequiredPasswordLength="6" minRequiredNonalphanumericCharacters="0" passwordAttemptWindow="10"
        applicationName="/" />
      </providers>
    </membership>

    <profile>
      <providers>
        <clear/>
        <add name="AspNetSqlProfileProvider" type="System.Web.Profile.SqlProfileProvider" connectionStringName="ApplicationServices" applicationName="/"/>
      </providers>
    </profile>

    <roleManager enabled="false">
      <providers>
        <clear/>
        <add name="AspNetSqlRoleProvider" type="System.Web.Security.SqlRoleProvider" connectionStringName="ApplicationServices" applicationName="/" />
        <add name="AspNetWindowsTokenRoleProvider" type="System.Web.Security.WindowsTokenRoleProvider" applicationName="/" />
      </providers>
    </roleManager>

  </system.web>

  <system.webServer>
    <modules runAllManagedModulesForAllRequests="true"/>
  </system.webServer>
</configuration>

احتوى دليل REST على مشروع ASP.NET فارغ تم إنشاؤه من VS 2010 ، وأضع ملف ASPX واحد في ذلك ، ومع ذلك لم تكن محتويات مجلد REST لديك لتكون مشروع جديد. مجرد إسقاط في ملف التكوين بعد أن يكون للدليل تطبيق مرتبط به يجب أن يعمل. يتبع التكوين لهذا المشروع:

<?xml version="1.0"?>
<configuration>
  <configSections>
    <section name="customBasicAuthentication" type="Thinktecture.CustomBasicAuthentication.CustomBasicAuthenticationSection, Thinktecture.CustomBasicAuthenticationModule"/>
  </configSections>
  <customBasicAuthentication
    enabled="true"
    realm="testdomain"
    providerName="AspNetSqlMembershipProvider"
    cachingEnabled="true"
    cachingDuration="15"
  requireSSL="false" />

  <system.web>
    <authentication mode="None"/>
    <authorization>
      <deny users="?"/>
    </authorization>

    <compilation debug="true" targetFramework="4.0" />
    <httpModules>
      <add name="CustomBasicAuthentication" type="Thinktecture.CustomBasicAuthentication.CustomBasicAuthenticationModule, Thinktecture.CustomBasicAuthenticationModule"/>
    </httpModules>
  </system.web>
</configuration>

آمل أن يلبي هذا احتياجاتك.

قد لا يكون هذا هو الحلول الأكثر أناقة ولكن أعتقد أنها بداية جيدة

1) إنشاء httpmodule.

2) التعامل مع الحدث الأصلي.

3) في معالج الأحداث ، تحقق من أن الطلب هو الدليل الذي تريد السماح به للوصول إليه.

4) إذا تم تعيين ملف تعريف ارتباط Auth يدويًا: (أو تعرف على ما إذا كان يمكنك العثور على طريقة أخرى الآن بعد أن لم تحدث التحكم والمصادقة بعد)

FormsAuthentication.SetAuthCookie("Anonymous", false);

5) لقد نسيت تقريبًا ، فأنت تريد التأكد من مسح ملف تعريف الارتباط المصادق إذا لم يكن الطلب للدليل الذي تريد منح الوصول إليه.

بعد النظر في تعليقاتك على إجابتي السابقة ، تساءلت عما إذا كان بإمكانك جعل تطبيق الويب الخاص بك أتمتة نشر تطبيق على دليل الراحة الخاص بك. من شأن ذلك أن يتيح لك الحصول على فوائد تطبيق ثانٍ ، وسيؤدي أيضًا إلى تقليل عبء النشر على مدراء النظام الخاص بك.

فكرتي هي أنه يمكنك وضع روتين في Application_Start طريقة global.asax التي من شأنها أن تحقق وجود دليل REST ، وأنه ليس لديه بالفعل تطبيق مرتبط به. في حالة إرجاع الاختبار بشكل صحيح ، فإن عملية ربط تطبيق جديد إلى دليل REST تحدث.

فكر آخر لدي هو أنه يمكنك استخدامه ويكس (أو تقنية نشر أخرى) لإنشاء حزمة تثبيت يمكن أن يقوم بها مدراءك لإنشاء التطبيق ، ومع ذلك لا أعتقد أن هذا تلقائي مثل وجود التطبيق يتكوين تبعية.

أدناه ، قمت بتضمين تنفيذ عينة يتحقق من IIS للحصول على دليل معين وتطبيق تطبيق عليه إذا لم يكن لديه بالفعل. تم اختبار الرمز مع IIS 7 ، ولكن يجب أن تعمل على IIS 6 كذلك.

//This is part of global.asax.cs
//This approach may require additional user privileges to query IIS

//using System.DirectoryServices;
//using System.Runtime.InteropServices;

protected void Application_Start(object sender, EventArgs evt)
{
  const string iisRootUri = "IIS://localhost/W3SVC/1/Root";
  const string restPhysicalPath = @"C:\inetpub\wwwroot\Rest";
  const string restVirtualPath = "Rest";

  if (!Directory.Exists(restPhysicalPath))
  {
    // there is no rest path, so do nothing
    return;
  }

  using (var root = new DirectoryEntry(iisRootUri))
  {
    DirectoryEntries children = root.Children;

    try
    {
      using (DirectoryEntry rest = children.Find(restVirtualPath, root.SchemaClassName))
      {
        // the above call throws an exception if the vdir does not exist
        return;
      }
    }
    catch (COMException e)
    {
      // something got unlinked incorrectly, kill the vdir and application
      foreach (DirectoryEntry entry in children)
      {
        if (string.Compare(entry.Name, restVirtualPath, true) == 0)
        {
          entry.DeleteTree();
        }     
      }
    }
    catch (DirectoryNotFoundException e)
    {
      // the vdir and application do not exist, add them below
    }

    using (DirectoryEntry rest = children.Add(restVirtualPath, root.SchemaClassName))
    {
      rest.CommitChanges();
      rest.Properties["Path"].Value = restPhysicalPath;
      rest.Properties["AccessRead"].Add(true);
      rest.Properties["AccessScript"].Add(true);
      rest.Invoke("AppCreate2", true);
      rest.Properties["AppFriendlyName"].Add(restVirtualPath);
      rest.CommitChanges();
    }
  }
}

جاءت أجزاء من هذا الرمز هنا. حظا سعيدا مع تطبيقك!

في .NET 4.5 يمكنك الآن تعيين

Response.SuppressFormsAuthenticationRedirect = true

تحقق من هذه الصفحة: https://msdn.microsoft.com/en-us/library/system.web.httpresponse.suppressformsauthenticationRex.aspx

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top