c# - 结合表单例份验证和基本身份验证

标签 c# asp.net authentication

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

我提出的解决方案似乎可行,但我是否遗漏了什么?

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

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

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

相关文章:

java - 如何增强 CXF 拦截器方法的回调处理程序

c# - 使用 mvvm 和 wpf 重用菜单

c# - 使用反射将对象数组转换为另一种类型的数组

c# - 依赖属性数据上下文

javascript - 如何在转发器控件中获取asp控件(_lblCouncils)的客户端ID?

c# - 如何保证同一时间只有一个用户可以执行一段代码

asp.net - 如何让asp.net下载动态csv

sharepoint - sharepoint 中区域的用途是什么? (Web 应用程序区域或身份验证区域或它们如何调用它)

java - 单击 "Login Button"不适用于 Selenium Java 代码

c# - Windows 窗体从其他线程更新控件