BCHAT采用DISCUZ!NT论坛的外置验证方式实例

2008年10月26日

BCHAT除了直接连接聊天室自身的数据库进行用户验证之外,还可以选择间接的MD5加密登录验证方法。这样可以让聊天室更好的和其他已有系统如论坛等相融合。其实质是:已有的其他用户验证系统独立进行用户身份验证,其验证过程与聊天室无关,用户验证通过以后再交给聊天室。

验证步骤如下:
步骤一、验证系统和聊天室双方约定登录验证密钥,如字符串:abcd;
步骤二、在聊天室配置文件中设置MD5KEY项的值为约定好的字符串,如:abcd;
步骤三、用户输入用户名和密码首先交给验证系统,验证系统访问外部数据库进行用户名密码验证,或者采用其他验证方式进行用户验证。该验证过程与聊天室无关。
步骤四、验证系统对通过验证的用户名如login123先进行“用户名+key”即“login123abcd”的MD5编码,然后跳转传递给聊天室端口的登录用户名参数,如http://host:port/?USER= login123&PASS= [MD5编码字符串],若需用到子房间,再加上参数&ROOMID=[子房间ID0-9]。
步骤五:聊天室检查所传过来的用户名和对应的MD5字符串是否由和验证系统双方约定的密钥产生的,如果是就让该用户进入聊天室。

聊天室的相关配置项:
MD5KEY=[如果采用MD5验证,则在这里设置约定的key]
MD5KEYLIMITTIME=[默认为0。为0时不作有效时间限制。为大于0的值时,则在该值指定的秒数内有效,作为密码的MD5值前面需要加上长度为10位的当前时间值以备比较,也就是:PASS=TIME+MD5(USER+TIME+KEY)]

如果用到影院看电影来比喻这个过程,那么就是:聊天室是播放大厅,验证系统是售票处。聊天室只认验证系统传过来的结果,就有如播放大厅只认售票处卖出去的门票。用户在验证系统买了门票以后,持票到播放大厅,播放大厅验证门票的正确与否,然后放用户进去。

下面就BCHAT与discuz!NT的登陆验证相结合做个实例说明。
discuz!NT可以配置用各种模板,默认的模板是在/config/general.config的“Templateid”配置项设置的。例如该项设置值为1,那么使用的默认模板就在/aspx/1目录下的。我们在/aspx/1目录下找个简单一点的文件来改动以生成聊天室的登陆入口文件,经查看发现其中的help.aspx结构比较简单,于是用它copy一个chat.aspx,然后把其中的help的内容掏掉,这样就具备了一个基本的具有登录验证功能的chat.aspx。在其中加上聊天室的房间列表和登录功能就可以了。加入的代码如下:

	if (userid==-1)
	{
 
	templateBuilder.Append("<p><br>您尚未登录,请先进行登录。<br><br></p>\r\n");
	}
	else
	{
            templateBuilder.Append("<style type=\"text/css\">\r\n");
            templateBuilder.Append("#listdiv{ width:500px; margin:20px 20px 20px 20px; }\r\n");
            templateBuilder.Append("#listdiv ul,li{ list-style:none; padding:0; }\r\n");
            templateBuilder.Append("#listdiv li{ width:220px; float:left; margin:0px;padding:0px; line-height:25px}\r\n");
            templateBuilder.Append("#listdiv p{color:Gray}\r\n");
            templateBuilder.Append("#listdiv span{color:Gray}\r\n");
            templateBuilder.Append("#listdiv .roomname{color:#886349}\r\n");
            templateBuilder.Append("</style>\r\n");
            templateBuilder.Append("<script language=\"JavaScript\" type=\"text/javascript\">\r\n");
            templateBuilder.Append("var focusok=false;\r\n");
            templateBuilder.Append("if (navigator.appName == \"Netscape\") {\r\n");
            templateBuilder.Append("	focusok=true;\r\n");
            templateBuilder.Append("}\r\n");
            templateBuilder.Append("vers = navigator.appVersion;\r\n");
            templateBuilder.Append("if (navigator.appName == \"Microsoft Internet Explorer\") {\r\n");
            templateBuilder.Append(" pos = vers.lastIndexOf('.'); \r\n");
            templateBuilder.Append(" vers = vers.substring(pos-1,vers.length); \r\n");
            templateBuilder.Append("}\r\n");
            templateBuilder.Append("proper_version = parseFloat(vers); \r\n");
            templateBuilder.Append("\r\n");
            templateBuilder.Append("if(proper_version>=5){\r\n");
            templateBuilder.Append("	focusok=true;\r\n");
            templateBuilder.Append("}\r\n");
            templateBuilder.Append("\r\n");
            templateBuilder.Append("var chat;\r\n");
            templateBuilder.Append("function launchchat() {\r\n");
            templateBuilder.Append("\r\n");
            templateBuilder.Append("  chat = window.open(\"\",\"chat\",\"top=0,left=0,toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=790,height=530\");\r\n");
            templateBuilder.Append("  if(focusok){\r\n");
            templateBuilder.Append("	chat.focus();\r\n");
            templateBuilder.Append("  }\r\n");
            templateBuilder.Append("  return true;\r\n");
            templateBuilder.Append("}\r\n");
            templateBuilder.Append("function b(port,host)\r\n");
            templateBuilder.Append("{\r\n");
            templateBuilder.Append("  	launchchat();\r\n");
            templateBuilder.Append("	chat.document.URL=\"chatlogin.aspx?port=\"+port+\"&host=\"+host;\r\n");
            templateBuilder.Append("}    \r\n");
            templateBuilder.Append("</"+"script>\r\n");
            templateBuilder.Append("\r\n");
            templateBuilder.Append("<div id=\"listdiv\">\r\n");
            templateBuilder.Append("<p>请点击聊天室名称前面的小圈进入聊天室:\r\n");
            templateBuilder.Append("</p>\r\n");
            templateBuilder.Append("<ul>  \r\n");
 
            OdbcConnection myConnection = new OdbcConnection("Dsn=chatdb;dbq=C:\\bchat\\db\\chatdb.mdb;driverid=25;fil=MS Access;maxbuffersize=2048;pagetimeout=5;uid=admin;pwd=pass");
            //OdbcConnection myConnection = new OdbcConnection("Dsn=chat;uid=chat;pwd=pass"); //如果是用MSSQL就用这行
 
            string cmdText = "SELECT [port],[roomname],[num],[host] FROM [room] order by [port]";
            OdbcCommand myCommand = new OdbcCommand(cmdText, myConnection);
 
            OdbcDataReader dr = null;
            try
            {
                myConnection.Open();
                dr = myCommand.ExecuteReader(CommandBehavior.CloseConnection);
                while (dr.Read())
                {
                    templateBuilder.Append("<li>\r\n");
                    templateBuilder.Append("<input name=\"r\" onclick=\"if(this.checked){b('"+dr.GetString(0)+"','"+dr.GetString(3)+"')}\" type=\"radio\">\r\n");
                    templateBuilder.Append("<span class=\"roomname\">"+dr.GetString(1)+"</span><span>("+Convert.ToString(dr.GetInt32(2))+"人)</span>\r\n");
                    templateBuilder.Append("</li>\r\n");
                }
                dr.Close();  
            }
            catch (OdbcException ex)
            {
                throw new Exception(ex.Message, ex);
            }
 
            templateBuilder.Append("</ul>\r\n");
            templateBuilder.Append("</div>\r\n");
	}

其中如果“userid==-1”就代表还没有登录论坛,提示用户先登录;否则就列出聊天室的房间列表,供用户选择登录。真正的登录操作则是通过chatlogin.aspx来完成。它从“username”变量提取已登录用户的用户名,然后做MD5KEY的运算,再提交给聊天室的入口。代码如下:

<%@ Page language="c#" AutoEventWireup="false" EnableViewState="false" Inherits="Discuz.Web.help" codepage=936 %>
<%@ Import namespace="System.Data" %>
<%@ Import namespace="Discuz.Common" %>
<%@ Import namespace="Discuz.Forum" %>
<%@ Import namespace="Discuz.Entity" %>
 
<script runat="server">
    public string host;
    public UInt32 port;
    public UInt32 roomid;
    public string name;
    public string pass;
    public string key;
    public UInt32 currenttime;
 
    override protected void OnInit(EventArgs e)
    {
	base.OnInit(e);
 
	if (userid==-1)
	{
		Response.Write("请先登陆.");
		Response.End();
		return;
	}
 
        host = Request.Params["host"];
        if (Request.Params["port"] != null)
        {
            port = Convert.ToUInt32(Request.Params["port"].ToString());
        }
        else
        {
            port = 2000;
        }
        if(port>65535){
            roomid=port %1000;
            port = Convert.ToUInt32(Math.Floor(port / 1000.0));
        }else{
            roomid=0;
        }
 
        name = username.ToString();
 
        key = "md5key";//此为登陆程序与聊天室程序约定的md5key,必须和聊天室启动配置ini文件中定义的MD5KEY一致
        DateTime dt = new DateTime(1970, 1, 1, 8, 0, 0);
        TimeSpan ts = DateTime.Now - dt;
        currenttime = Convert.ToUInt32(ts.TotalSeconds);
        pass = name + key;        
        pass = MyMd5(pass);
        //如果设置了MD5KEYLIMITTIME则用下面的办法:
        //pass = name + currenttime.ToString() + key;
        //pass = MyMd5(pass);
        //pass = currenttime.ToString() + pass;
    }
 
    static string MyMd5(string str)
    {
        //byte[] b = System.Text.Encoding.Default.GetBytes(str);
        byte[] b = System.Text.Encoding.GetEncoding("gb2312").GetBytes(str);
        System.Security.Cryptography.MD5 md5 = System.Security.Cryptography.MD5.Create();
        byte[] d = md5.ComputeHash(b);
        string r = "";
        for (int i = 0; i < d.Length; i++)
            r += d[i].ToString("x").PadLeft(2, '0');
        return r;
    }
 
</script>
 
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title>聊天室的MD5KEY方式登陆</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
 
    </div>
    </form>
 
    <form name="loginform" id="loginform" action="http://<%=host%>:<%=port%>/" method="post">
    <input type="hidden" name="USER" value="<%=name%>" />
    <input type="hidden" name="PASS" value="<%=pass%>" />
    <input type="hidden" name="ROOMID" value="<%=roomid%>" />
    聊天室登陆中...
    </form> 
    <script language="javascript" type="text/javascript">
        document.loginform.submit();
    </script>     
 
</body>
</html>

注意这里把输出的页面编码设成了936,也就是gb2312,这是由于聊天室用的是gb2312编码。
完整的chat.aspx和chatlogin.aspx可以软件安装目录下的docs/md5logincodeexample/discuznt目录中找到。该目录下还有和其他论坛结合验证的例子。
如果在discuz!NT的aspx目录下有多个子目录,也就是用了多个模板,那么需要把chat.aspx和chatlogin.aspx两个文件复制到每个目录中去。

蓝天.收藏与分享

相关日志:

标签: , , , ,
归类: BCHAT

评论暂缺

(Required)
(Required, will not be published)