通过HttpModule调用服务初始化函数

时间:2012-12-02 12:41:11

标签: asp.net wcf-data-services custom-authentication

我编写了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方法。我是否必须明确地添加一些东西才能让它运行?

0 个答案:

没有答案