我有一些核心 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/