结合表单认证和基本认证 [英] Combining Forms Authentication and Basic Authentication

查看:217
本文介绍了结合表单认证和基本认证的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一些核心的ASP code,我想通过安全网页(使用窗体身份验证)(使用基本身份验证),并通过Web服务公开两种。

这是我想出似乎工作,但解决的办法我缺少什么吗?

首先,整个网站HTTPS下运行。

站点设置为使用Forms身份验证在web.config中

 <身份验证模式=表格>
  <形式loginUrl =〜/的Login.aspx超时=2880/>
< /认证>
<授权>
  <拒绝用户= /&gt的帮助?
< /授权>

然后我重写Global.asax中的AuthenticateRequest,触发基本身份验证的Web服务页面:

 无效Application_AuthenticateRequest(对象发件人,EventArgs的发送)
{
    //检查请求的Web服务 - 这是唯一的页面
    //应该接受基本身份验证
    HttpApplication的应用程序=(HttpApplication的)寄件人;
    如果(app.Context.Request.Path.StartsWith(/服务/ MyService.asmx))
    {        如果(HttpContext.Current.User!= NULL)
        {
            Logger.Debug(+ HttpContext.Current.User.Identity.NameWeb服务用户要求);
        }
        其他
        {
            Logger.Debug(空用户 - 使用基本身份验证);            HttpContext的CTX = HttpContext.Current;            布尔认证= FALSE;            //看授权头
            字符串authHeader = ctx.Request.Headers [授权];            如果(authHeader = NULL&放大器;!&安培; authHeader.StartsWith(基本))
            {
                //提取头凭据
                字符串[] =凭证extractCredentials(authHeader);                //因为我仍在使用的形式提供,这应该
                //以相同的方式验证为一个表格登录
                如果(Membership.ValidateUser(凭证[0],凭证[1]))
                {
                    //创建主体 - 也可以获取用户角色
                    GenericIdentity ID =新GenericIdentity(凭证[0],CustomBasic);
                    的GenericPrincipal P =新的GenericPrincipal(ID,NULL);
                    ctx.User = P;                    验证= TRUE;
                }
            }            //发出身份验证头触发客户端身份验证
            如果(认证== FALSE)
            {
                ctx.Response.Status code = 401;
                ctx.Response.AddHeader(
                    WWW身份验证,
                    基本境界= \\本地主机\\);
                ctx.Response.Flush();
                ctx.Response.Close();                返回;
            }
        }
    }
}私人的String [] extractCredentials(字符串authHeader)
{
    //去掉基本
    字符串连接codedUserPass = authHeader.Substring(6).Trim();    //这是正确的编码
    编码编码= Encoding.GetEncoding(ISO-8859-1);
    字符串为userpass = encoding.GetString(Convert.FromBase64String(EN codedUserPass));
    INT分离= userPass.IndexOf(':');    字符串[] =凭据新的字符串[2];
    凭证[0] = userPass.Substring(0,分离器);
    凭证[1] = userPass.Substring(隔板+ 1);    返回证书;
}


解决方案

.NET 4.5有一个新的响应属性:燮pressFormsAuthenticationRedirect 。当设置为true,它将prevents重定向401响应该网站的登录页面。您可以使用您的global.asax.cs以下code段启用例如基本身份验证在/健康检查的文件夹。

  ///<总结>
  ///验证应用程序的请求。
  ///基本身份验证用于以/健康检查开始的请求。
  ///的健康检查IIS文件夹的身份验证设置:
  /// - Windows身份验证:禁用。
  /// - 基本验证:启用。
  ///< /总结>
  ///< PARAM NAME =发件人>该事件的源< /参数>
  ///< PARAM NAME =E>将<见CREF =System.EventArgs/>包含事件数据< /参数>
  保护无效Application_AuthenticateRequest(对象发件人,EventArgs的发送)
  {
     VAR应用程序=(HttpApplication的)寄件人;
     如果(application.Context.Request.Path.StartsWith(/健康检查,​​StringComparison.OrdinalIgnoreCase))
     {
        如果(HttpContext.Current.User == NULL)
        {
           VAR语境= HttpContext.Current;
           context.Response.Sup pressFormsAuthenticationRedirect = TRUE;
        }
     }
  }

I have some core ASP code that I want to expose both by secure web pages (using Forms Authentication) and via web services (using Basic Authentication).

The solution that I've come up with seems to work, but am I missing anything here?

First, the whole site runs under HTTPS.

Site is set to use Forms authentication in web.config

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

Then I override the AuthenticateRequest in Global.asax, to trigger Basic Authentication on the web service pages:

void Application_AuthenticateRequest(object sender, EventArgs e)
{
    //check if requesting the web service - this is the only page
    //that should accept Basic Authentication
    HttpApplication app = (HttpApplication)sender;
    if (app.Context.Request.Path.StartsWith("/Service/MyService.asmx"))
    {

        if (HttpContext.Current.User != null)
        {
            Logger.Debug("Web service requested by user " + HttpContext.Current.User.Identity.Name);
        }
        else
        {
            Logger.Debug("Null user - use basic auth");

            HttpContext ctx = HttpContext.Current;

            bool authenticated = false;

            // look for authorization header
            string authHeader = ctx.Request.Headers["Authorization"];

            if (authHeader != null && authHeader.StartsWith("Basic"))
            {
                // extract credentials from header
                string[] credentials = extractCredentials(authHeader);

                // because i'm still using the Forms provider, this should
                // validate in the same way as a forms login
                if (Membership.ValidateUser(credentials[0], credentials[1]))
                {
                    // create principal - could also get roles for user
                    GenericIdentity id = new GenericIdentity(credentials[0], "CustomBasic");
                    GenericPrincipal p = new GenericPrincipal(id, null);
                    ctx.User = p;

                    authenticated = true;
                }
            }

            // emit the authenticate header to trigger client authentication
            if (authenticated == false)
            {
                ctx.Response.StatusCode = 401;
                ctx.Response.AddHeader(
                    "WWW-Authenticate",
                    "Basic realm=\"localhost\"");
                ctx.Response.Flush();
                ctx.Response.Close();

                return;
            }
        }
    }            
}

private string[] extractCredentials(string authHeader)
{
    // strip out the "basic"
    string encodedUserPass = authHeader.Substring(6).Trim();

    // that's the right encoding
    Encoding encoding = Encoding.GetEncoding("iso-8859-1");
    string userPass = encoding.GetString(Convert.FromBase64String(encodedUserPass));
    int separator = userPass.IndexOf(':');

    string[] credentials = new string[2];
    credentials[0] = userPass.Substring(0, separator);
    credentials[1] = userPass.Substring(separator + 1);

    return credentials;
}

解决方案

.Net 4.5 has a new Response property: SuppressFormsAuthenticationRedirect. When set to true it prevents redirecting a 401 response to the login page of the website. You can use the following code snippet in your global.asax.cs to enable Basic Authentication for e.g. the /HealthCheck folder.

  /// <summary>
  /// Authenticates the application request.
  /// Basic authentication is used for requests that start with "/HealthCheck".
  /// IIS Authentication settings for the HealthCheck folder:
  /// - Windows Authentication: disabled.
  /// - Basic Authentication: enabled.
  /// </summary>
  /// <param name="sender">The source of the event.</param>
  /// <param name="e">A <see cref="System.EventArgs"/> that contains the event data.</param>
  protected void Application_AuthenticateRequest(object sender, EventArgs e)
  {
     var application = (HttpApplication)sender;
     if (application.Context.Request.Path.StartsWith("/HealthCheck", StringComparison.OrdinalIgnoreCase))
     {
        if (HttpContext.Current.User == null)
        {
           var context = HttpContext.Current;
           context.Response.SuppressFormsAuthenticationRedirect = true;
        }
     }
  }

这篇关于结合表单认证和基本认证的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆