现在的位置: 首页 > 综合 > 正文

如何在Web应用程序中实现自定义身份验证对话框

2013年11月07日 ⁄ 综合 ⁄ 共 4657字 ⁄ 字号 评论关闭

这个标题可能并不太准确,我这样来描述一下我们的意图吧:

我们知道在Web应用程序中有几种主要的身份验证方式,典型的就是Windows验证和Forms验证。如果设置为Windows验证的话,那么既可以自动使用用户当前身份登录(如果在一个可信任的环境中),也可以弹出一个对话框要求用户输入用户名和密码。

再来Forms验证,顾名思义,它是有一个表单来进行验证的,在web.config中,我们通常需要指定一个loginUrl。这样用户如果没有得到授权,则需要转到这个页面输入用户名和密码。

但是,也有的朋友跟我提到,如果我们使用Forms验证,能不能也弹出一个对话框让用户输入用户名和密码呢?这的确是一个不错的问题。

可惜的是,Forms验证无法提供这样的功能,但我们确实可以通过自定义验证来实现

using System;
using System.Text;
using System.Web;
using System.Security.Principal;

namespace DataServiceAuthenticationModule
{
    public class AuthenticationModule : IHttpModule
    {
        const string accessDeniedStatus = "拒绝访问";
        const string accessDeniedHtml = "401 您的请求被拒绝,因为没有通过身份验证";
        const string realmFormatString = "Basic realm=/"{0}/"";
        const string authServerHeader = "WWW-Authenticate";
        const string authClientHeader = "Authorization";
        const string basicAuth = "Basic";

        #region IHttpModule 成员

        public void Dispose()
        {

        }

        public void Init(HttpApplication context)
        {
            context.AuthenticateRequest += new EventHandler(context_AuthenticateRequest);
        }

        void context_AuthenticateRequest(object sender, EventArgs e)
        {
            HttpApplication context = (HttpApplication)sender;

            if (context.Request.Headers["Authorization"] == null)
            {
                UnAuthorization(context);

            }

            else
            {

                string credential = ASCIIEncoding.ASCII.GetString(Convert.FromBase64String(GetBase64CredentialsFromHeader()));
                string[] usernameandpassword = credential.Split(':');
                bool isAuthenticate=Authenticate(usernameandpassword[0], usernameandpassword[1]);

                if (!isAuthenticate)
                {
                    UnAuthorization(context);
                }
                context.Context.User= new MyPrinciple(
                    new MyIdentity(usernameandpassword[0], isAuthenticate ));
            }

        }

        private static void UnAuthorization(HttpApplication context)
        {
            context.Response.ContentEncoding = Encoding.GetEncoding("GB2312");
            context.Response.StatusCode = 401;
            context.Response.StatusDescription = accessDeniedStatus;
            context.Response.Write(accessDeniedHtml);
            // TODO: not sure this is quite right wrt realm.
            context.Response.AddHeader(authServerHeader,
                string.Format(realmFormatString, context.Request.Url.GetLeftPart(UriPartial.Authority)));
        }

        bool Authenticate(string username, string password)
        {
            //your code logic here to authenticate user

            if (username !="chenxizhang" || password!="password") return false;
            else
                return true;



        }

        string GetBase64CredentialsFromHeader()
        {

            string credsHeader =HttpContext.Current.Request.Headers[authClientHeader];

            string creds = null;



            int credsPosition =

              credsHeader.IndexOf(basicAuth, StringComparison.OrdinalIgnoreCase);



            if (credsPosition != -1)
            {

                credsPosition += basicAuth.Length + 1;



                creds = credsHeader.Substring(credsPosition,

                  credsHeader.Length - credsPosition);

            }

            return (creds);

        }



        #endregion
    }

    public class MyPrinciple : IPrincipal
    {

        private IIdentity _id;

        public MyPrinciple(IIdentity id)
        {

            _id = id;

        }

        public IIdentity Identity
        {

            get { return _id; }

        }



        public bool IsInRole(string role)
        {

            throw new NotImplementedException();

        }



    }



    public class MyIdentity : IIdentity
    {

        private bool _isAuthenticated = false;

        private string _name;

        public MyIdentity(string name, bool isAuthenticated)
        {

            _isAuthenticated = isAuthenticated;

            _name = name;

        }

        public string AuthenticationType
        {

            get { throw new NotImplementedException(); }

        }



        public bool IsAuthenticated
        {

            get { return _isAuthenticated; }

        }

        public string Name
        {

            get { return _name; }

        }



    }

}

image

那么,在后面到底发生了什么呢?是怎么弹出这个对话框的呢?

image

这个对话框其实是浏览器弹出来的。浏览器收到了一个Response,内容为Unauthorized,所以它知道服务器端需要进行验证,所以它弹出了这个对话框。为了说明这一点,我们可以来看一下其他的浏览器弹出的对话框。下面这个是Google chrome浏览器弹出的

image

下面这个是Mozilla Firefox浏览器弹出的

image

那么,接下来我们看看,我们输入的用户名和密码是怎么发送给服务器的呢

image

我们看到了这样一串文本:

Y2hlbnhpemhhbmc6cGFzc3dvcmQ=

这里就是包含了我们输入的用户名和密码。注意,它并没有被加密。我们可以通过下面的几行代码很容易地将其还原为明文的字符串

using System;
using System.Text;

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            string token = "Y2hlbnhpemhhbmc6cGFzc3dvcmQ=";
            byte[] buffer = Convert.FromBase64String(token);
            string output = Encoding.ASCII.GetString(buffer);
            Console.WriteLine(output);
            Console.Read();
        }
    }
}
image 
这是用冒号隔开的字符串。
 

抱歉!评论已关闭.