• 使用java编写SmartFoxServer自定义安全验证登录扩展


    最近接触的东西有点杂,在写SmartFoxServer(以下简称SFS)服务端扩展时发现actionscript竟然只支持1.0,无奈只好用从来没有接触过的java来编写,参考官方cookbook及手册,成功实现了自定义安全验证登录扩展。
    系统用的是CentOS5.2(x86_64),数据库是Oracle 11g,SFS版本为1.6.6。

    1. 配置

      数据库DEMO中的USERS表结构:

      CREATE TABLE "DEMO"."USERS"
      (
      "USERID" NUMBER(38,0) NOT NULL ENABLE,
      "USERNAME" VARCHAR2(20) NOT NULL ENABLE,
      "USERPWD" VARCHAR2(32) NOT NULL ENABLE,
      "USEREMAIL" VARCHAR2(100),
       CONSTRAINT "TABLE1_PK" PRIMARY KEY ("USERID") ENABLE
      ) ;
      

      将连接java连接oracle的驱动(oracle/product/11.1.0/db_1/jdbc/lib/ojdbc6.jar,这里我用的是JDK1.6,所以用ojdbc6.jar,根据自己的需要复制驱动)复制到(SFS_PRO_1.6.6/jre/lib/ext/)下,然后修改SFS根目录下的config.xml,在Zones节点内加入如下Zone配置:

      	
      		
      	
      
      	
      		
      	
      
      	
      
      		oracle.jdbc.driver.OracleDriver
      		jdbc:oracle:thin:@localhost:1521:DEMO
      
      		demo
      demo
      
      		< ![CDATA[SELECT COUNT(*) FROM USERS]]>
      
      		10
      		10
      
      		fail
      		5000
      
      	
      
      
      

      这里根据自己数据库配置来设置驱动、连接字符串、用户名、密码,如果用的是mysql,那么驱动和连接字符串应该如下:

      com.mysql.jdbc.Driver
      jdbc:mysql://localhost:3306/DEMO
      
    2. 编写扩展

      在写扩展之前,需要了解一下安全验证的机制,借用一下官方的图示:
      secureLoginDiagram
      第一步:从服务器获取随机码,把用户输入密码用md5加密,然后再把随机码和加密后的md5码再用md5加密,并发送给服务器。
      第二步:服务器端从数据库取出经过md5加密的用户密码,同样用md5再加密一次随机码和取出的md5密码,然后和客户端发来的hash过的字符进行对比,来验证登录。

      理解了这次,就可以开始编写Zone配置里的扩展demo_login了,关于扩展的具体说明,看官方手册就可以了,这里给出源码借参考:

      import java.nio.channels.SocketChannel;
      import java.util.*;
      
      import it.gotoandplay.smartfoxserver.crypto.MD5;
      import it.gotoandplay.smartfoxserver.data.*;
      import it.gotoandplay.smartfoxserver.db.*;
      import it.gotoandplay.smartfoxserver.exceptions.*;
      import it.gotoandplay.smartfoxserver.extensions.*;
      import it.gotoandplay.smartfoxserver.lib.ActionscriptObject;
      import it.gotoandplay.smartfoxserver.events.InternalEventObject;
      
      public class demo_login extends AbstractExtension
      {
      	private ExtensionHelper helper;
      	private Zone currentZone;
      	private DbManager db;
      
      	public void init()
      	{
      		helper = ExtensionHelper.instance();
      		this.currentZone = helper.getZone(this.getOwnerZone());
      	}
      
      	public void destroy()
      	{
      		trace("Extension destroyed");
      	}
      
      	public void handleRequest(String cmd, ActionscriptObject ao, User u, int fromRoom)
      	{
      		// Your code here
      	}
      
      	public void handleRequest(String cmd, String params[], User u, int fromRoom)
      	{
      		// Your code here
      	}
      
      	/**
      	 * Handle Internal Server Events
      	 *
      	 * @param ieo		the event object
      	 */
      	public void handleInternalEvent(InternalEventObject ieo)
      	{
      		if (ieo.getEventName().equals("loginRequest"))
      		{
      			// 根据配置文件里的DatabaseManager配置获得当前Zone的数据库操作对象
      			db = this.currentZone.dbManager;
      			ActionscriptObject response = new ActionscriptObject();
      			User loginUser = null;
      
      			// 获取用户名
      			String nick = ieo.getParam("nick");
      			// 获取客户端利用服务器加密字符串和用户密码加密后MD5密码
      			String ClientPassword = ieo.getParam("pass");
      			// 获取服务器socket通道
      			SocketChannel chan = (SocketChannel)ieo.getObject("chan");
      			// 根据socket通道生成加密字符
      			String ServerRandom = helper.getSecretKey(chan);
      			// 获取数据库中用户的密码
      			ArrayList arrList = db.executeQuery("SELECT USERPWD FROM USERS WHERE USERNAME='"+nick+"'");
      			String ServerPassword = "";
      			boolean IsLogin = false;
      			if (arrList.size() < = 0)
      			{
      				response.put("_cmd", "loginKO");
      				response.put("err", "用户名不存在,登录失败。");
      			}
      			else
      			{
      				// 获取数据库密码
      				DataRow dr = arrList.get(0);
      				String dbpass = dr.getItem("USERPWD");
      				// 根据服务器加密字符和数据库用户密码,生成服务器端的混合MD5密码
      				ServerPassword = MD5.instance().getHash(ServerRandom + dbpass);
      				IsLogin = (ClientPassword.equals(ServerPassword)) ? true : false;
      				if (IsLogin)
      				{
      					try
      					{
      						// 登录成功
      						loginUser = helper.canLogin(nick, ClientPassword, chan, this.currentZone.getName());
      						response.put("_cmd", "loginOK");
      						response.put("id", String.valueOf(loginUser.getUserId()));
      						response.put("name", loginUser.getName());
      					}
      					catch (LoginException e)
      					{
      						// 登录失败
      						response.put("_cmd", "loginKO");
      						response.put("err", e.getMessage());
      					}
      				}
      				else
      				{
      					response.put("_cmd", "loginKO");
      					response.put("err", "认证失败.");
      				}
      			}
      
      			LinkedList linkedlist = new LinkedList();
      			linkedlist.add(chan);
      			// 返回结果给客户端
      			this.sendResponse(response, -1, null, linkedlist);
      			if (IsLogin)
      				helper.sendRoomList(chan);
      		}
      	}
      }
      

      这里有个关键点需要注意:配置文件中Zone标签的属性customLogin要设置成true才能使服务端响应loginRequest事件。

    3. 客户端处理

      服务端的验证结果信息将通过客户端SmartFoxClient对象的onExtensionResponse返回,下面是该事件监听函数:

      private function onExtensionResponseHandler(e:SFSEvent):void
      {
      	// 数据传输类型
      	var type:String = e.params.type;
      	// 用Object类型接收数据
      	var data:Object = e.params.dataObj;
      	var cmd:String = data._cmd;
      	switch (cmd)
      	{
      		case "loginKO":
      			this._labWelcome.setText(data.err);
      			break;
      		case "loginOK":
      			_SFSClient.myUserId = data.id;
      			_SFSClient.myUserName = data.name;
      			initResources();
      			break;
      		default:
      			this._labWelcome.setText(data.err);
      			break;
      	}
      }
      
  • 相关阅读:
    手机端不加载js文件,PC端要加载js文件
    JS数组去重和取重
    jquery遍历一个数组
    2个轮播地址
    动感Loading文字
    仿265网站LOGO,会盯着你看的眼睛
    git学习
    c++ primer 5th 笔记:第十一章
    c++ primer 5th 笔记:第十章
    c++ primer 5th 笔记:第九章
  • 原文地址:https://www.cnblogs.com/tianliangle/p/2339018.html
Copyright © 2020-2023  润新知