结合表单认证和基本认证 [英] Combining Forms Authentication and Basic Authentication
问题描述
我有一些核心的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屋!