我编写了WCF数据服务,无需身份验证即可完美运行。 然后我想通过在应用程序中添加HttpModule来添加一些身份验证代码,如下所示:
public class BasicIdentity : IIdentity
{
string _name;
public BasicIdentity(string name)
{
this._name = name;
}
string IIdentity.AuthenticationType
{
get { return "Custom SCHEME"; }
}
bool IIdentity.IsAuthenticated
{
get { return true; }
}
string IIdentity.Name
{
get { return _name; }
}
}
public class BasicPrincipal : IPrincipal
{
string[] _roles;
IIdentity _identity;
public BasicPrincipal(string name, params string[] roles)
{
this._roles = roles;
this._identity = new CustomIdentity(name);
}
public IIdentity Identity
{
get { return _identity; }
}
public bool IsInRole(string role)
{
return _roles.Contains(role);
}
}
public class BasicAuthenticationProvider
{
public static bool Authenticate(HttpContext context)
{
//if (!HttpContext.Current.Request.IsSecureConnection)
// return false;
if (!HttpContext.Current.Request.Headers.AllKeys.Contains("Authorization"))
return false;
string authHeader = HttpContext.Current.Request.Headers["Authorization"];
IPrincipal principal;
if (TryGetPrincipal(authHeader, out principal))
{
HttpContext.Current.User = principal;
return true;
}
return false;
}
private static bool TryGetPrincipal(string authHeader, out IPrincipal principal)
{
//
// WARNING:
// our naive – easily mislead authentication scheme
// blindly trusts the caller.
// a header that looks like this:
// ADMIN username
// will result in someone being authenticated as an
// administrator with an identity of ‘username’
// i.e. not exactly secure!!!
//
//var protocolParts = authHeader.Split(' ');
//if (protocolParts.Length != 2)
//{
// principal = null;
// return false;
//}
//else if (protocolParts[0] == "ADMIN")
//{
// principal = new CustomPrincipal(
// protocolParts[1],
// "Administrator", "User"
// );
// return true;
//}
//else if (protocolParts[0] == "USER")
//{
// principal = new CustomPrincipal(
// protocolParts[1],
// "User"
// );
// return true;
//}
//else
//{
// principal = null;
// return false;
//}
var creds = ParseAuthHeader(authHeader);
if (creds != null && TryGetPrincipal(creds, out principal))
return true;
principal = null;
return false;
}
private static string[] ParseAuthHeader(string authHeader)
{
// Check this is a Basic Auth header
if (
authHeader == null ||
authHeader.Length == 0 ||
!authHeader.StartsWith("Basic")
) return null;
// Pull out the Credentials with are seperated by ':' and Base64 encoded
string base64Credentials = authHeader.Substring(6);
string[] credentials = Encoding.ASCII.GetString(
Convert.FromBase64String(base64Credentials)
).Split(new char[] { ':' });
if (credentials.Length != 2 ||
string.IsNullOrEmpty(credentials[0]) ||
string.IsNullOrEmpty(credentials[0])
) return null;
// Okay this is the credentials
return credentials;
}
private static bool TryGetPrincipal(string[] creds, out IPrincipal principal)
{
if (creds[0] == "Administrator" && creds[1] == "SecurePassword")
{
principal = new GenericPrincipal(
new GenericIdentity("Administrator"),
new string[] { "Administrator", "User" }
);
return true;
}
else if (creds[0] == "JoeBlogs" && creds[1] == "Password")
{
principal = new GenericPrincipal(
new GenericIdentity("JoeBlogs"),
new string[] { "User" }
);
return true;
}
else
{
principal = null;
return false;
}
}
}
public class BasicAuthenticationModule : IHttpModule
{
public void Init(HttpApplication context)
{
context.AuthenticateRequest
+= new EventHandler(context_AuthenticateRequest);
}
void context_AuthenticateRequest(object sender, EventArgs e)
{
HttpApplication application = (HttpApplication)sender;
if (!BasicAuthenticationProvider.Authenticate(application.Context))
{
application.Context.Response.Status = "401 Unauthorized";
application.Context.Response.StatusCode = 401;
application.Context.Response.AddHeader("WWW-Authenticate", "Basic");
application.CompleteRequest();
}
}
public void Dispose() { }
}
这里BasicAuthenticationModule在web.config中注册为
<system.web>
<compilation debug="true" targetFramework="4.0">
<assemblies>
<add assembly="System.Data.Entity, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
</assemblies>
</compilation>
<httpModules>
<add name="BasicAuthenticationModule"
type="ODataEmptyWebApp.BasicAuthenticationModule"/>
</httpModules>
</system.web>
现在,当我在浏览器中运行WCF数据服务时,它会询问我身份验证窗口。 当我输入无效凭据时,它会继续询问正确的凭据,当我提供正确的凭据时,即Administrator / SecuredPassword,它会关闭窗口并显示空白页面。页面的源代码如下:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML><HEAD>
<META http-equiv="Content-Type"
content="text/html; charset=windows-1252"></HEAD>
<BODY></BODY></HTML>
当我调试代码时,我发现它没有调用我在添加HttpModule之前调用的WCF数据服务的Initialize方法。
我没理解为什么控件没有传递给Initialize方法。我是否必须明确地添加一些东西才能让它运行?