我有一些核心 ASP 代码,我想通过安全网页(使用表单例份验证)和 Web 服务(使用基本身份验证)公开这些代码。

我想出的解决方案似乎有效,但我在这里遗漏了什么吗?

首先,整个站点在 HTTPS 下运行。

站点设置为在 web.config 中使用表单例份验证

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

然后我覆盖 Global.asax 中的 AuthenticateRequest,以触发 Web 服务页面上的基本身份验证:
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 有一个新的 Response 属性: SuppressFormsAuthenticationRedirect 。当设置为 true 时,它​​会阻止将 401 响应重定向到网站的登录页面。您可以在 global.asax.cs 中使用以下代码片段来启用基本身份验证,例如/HealthCheck 文件夹。

  /// <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;
        }
     }
  }

关于c# - 结合表单认证和基本认证,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/16830243/

10-14 15:39