关闭一个子目录的ASP.Net WebForms身份验证

Kei*_*ith 16 asp.net authentication web-config http http-status-code-401

我有一个包含WebForms和MVC页面的大型企业应用程序.它具有我不想更改的现有身份验证和授权设置.

WebForms身份验证在web.config中配置:

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

 <authorization>
  <deny users="?" />
 </authorization>
Run Code Online (Sandbox Code Playgroud)

到目前为止相当标准.我有一个REST服务,它是这个大型应用程序的一部分,我想使用HTTP身份验证代替这一项服务.

因此,当用户尝试从REST服务获取JSON数据时,它会返回HTTP 401状态和WWW-Authenticate标头.如果他们以正确形成的HTTP Authorization响应进行响应,则允许他们进入.

问题是,WebForms的覆盖这个处于较低的水平 - 如果返回401(未授权)它将覆盖与302(重定向到登录页面).这在浏览器中很好,但对REST服务没用.

我想关闭web.config中的身份验证设置,覆盖'rest'文件夹:

 <location path="rest">
  <system.web>
   <authentication mode="None" />
   <authorization><allow users="?" /></authorization>
  </system.web>
 </location>
Run Code Online (Sandbox Code Playgroud)

授权位工作正常,但认证线(<authentication mode="None" />)导致异常:

在应用程序级别之外使用注册为allowDefinition ='MachineToApplication'的部分是错误的.

我在应用程序级别配置它 - 它位于根web.config中 - 并且该错误适用于子目录中的web.configs.

如何覆盖身份验证,以便该站点的所有其余部分都使用WebForms身份验证,而这个目录不使用任何身份验证?

这类似于另一个问题:与ASP.NET MVC JSON请求401响应代码,但我不是在寻找相同的解决方案-我不想只是删除WebForms的认证和全球范围内添加新的自定义代码,还有远涉及很多风险和工作.我想只更改配置中的一个目录.

更新

我想设置一个Web应用程序,并希望所有WebForms页面和MVC视图都使用WebForms身份验证.我希望一个目录使用基本的HTTP身份验证.

请注意,我说的是身份验证,而不是授权.我希望REST调用带有HTTP头中的用户名和密码,我希望WebForm和MVC页面附带来自.Net的身份验证cookie - 在任何一种情况下,都会对我们的数据库进行授权.

我不想重写WebForms身份验证并滚动我自己的cookie - 这似乎是将HTTP授权的REST服务添加到应用程序的唯一方法,这似乎很荒谬.

我无法添加其他应用程序或虚拟目录 - 它必须作为一个应用程序.

gbs*_*gbs 7

如果"rest"只是你根目录中的一个文件夹,那么你几乎就在那里:删除认证线即

<location path="rest">
  <system.web>
      <authorization>
        <allow users="*" />
      </authorization>
  </system.web>
 </location>
Run Code Online (Sandbox Code Playgroud)

或者,您可以将web.config添加到您的rest文件夹中,然后执行以下操作:

<system.web>
     <authorization>
          <allow users="*" />
     </authorization>
</system.web>
Run Code Online (Sandbox Code Playgroud)

检查一下.


Kei*_*ith 4

我已经用混乱的方式解决了这个问题 - 通过欺骗所有现有页面的 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(','));

}
Run Code Online (Sandbox Code Playgroud)

我对此并不是很满意——这似乎是一次可怕的黑客攻击和重新发明轮子,但看起来这是我的表单验证页面和 HTTP 验证 REST 服务工作的唯一方法同一个应用程序。