使用java编写SmartFoxServer自定义安全验证登录扩展
2012-02-05 15:21
645 查看
最近接触的东西有点杂,在写SmartFoxServer(以下简称SFS)服务端扩展时发现actionscript竟然只支持1.0,无奈只好用从来没有接触过的java来编写,参考官方cookbook及手册,成功实现了自定义安全验证登录扩展。
系统用的是CentOS5.2(x86_64),数据库是Oracle 11g,SFS版本为1.6.6。
将连接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配置:
这里根据自己数据库配置来设置驱动、连接字符串、用户名、密码,如果用的是mysql,那么驱动和连接字符串应该如下:
第一步:从服务器获取随机码,把用户输入密码用md5加密,然后再把随机码和加密后的md5码再用md5加密,并发送给服务器。
第二步:服务器端从数据库取出经过md5加密的用户密码,同样用md5再加密一次随机码和取出的md5密码,然后和客户端发来的hash过的字符进行对比,来验证登录。
理解了这次,就可以开始编写Zone配置里的扩展demo_login了,关于扩展的具体说明,看官方手册就可以了,这里给出源码借参考:
这里有个关键点需要注意:配置文件中Zone标签的属性customLogin要设置成true才能使服务端响应loginRequest事件。
系统用的是CentOS5.2(x86_64),数据库是Oracle 11g,SFS版本为1.6.6。
配置
数据库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
编写扩展
在写扩展之前,需要了解一下安全验证的机制,借用一下官方的图示:第一步:从服务器获取随机码,把用户输入密码用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事件。
客户端处理
服务端的验证结果信息将通过客户端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; } }
相关文章推荐
- 使用java编写SmartFoxServer自定义安全验证登录扩展
- Java安全学习笔记(六)-使用消息摘要验证口令
- jsf的初步使用(包括jsf框架的引入、用户登录、自定义表单验证、valueChangeEvent值变更事件处理做的级联下拉框)
- 在Jmeter中使用自定义编写的Java测试代码
- 面向 Java 开发人员的 Ajax: 使用 Jetty 和 Direct Web Remoting 编写可扩展的 Comet 应用程序
- 用LinQ扩展方法,泛型扩展方法,实现自定义验证字符是否空、对象是否为null,及泛型约束使用,Action的使用
- 面向 Java 开发人员的 Ajax: 使用 Jetty 和 Direct Web Remoting 编写可扩展的 Comet 应用程序
- 使用 XSLT 和 Java 扩展验证 XML 文档中的复杂约束
- 使用Java的Frame类编写的QQ登录界面
- WCF开发-使用证书文件配置基于自定义X509证书验证的消息安全模式
- [Java]利用拦截器和自定义注解做登录以及权限验证
- Java Swing界面编程(23)---事件处理:编写用户验证登录用例
- 使用自定义验证组件库扩展 Windows 窗体
- 在java程序中,使用sAMAccountName作为登录名通过LDAP目录库验证
- Rational Functional Tester Proxy SDK 开发,第 3 部分: 使用 Proxy SDK 扩展 Java GUI 组件可捕获的验证数据
- JAVA实现:使用sAMAccountName作为登录名通过LDAP目录库验证
- JAVA Web 安全机制----使用filter验证session用户和页面缓存问题处理
- 高级 XML 验证-使用 XSLT 和 Java 扩展验证 XML 文档中的复杂约束
- 在Jmeter中使用自定义编写的Java测试代码
- 【MSDN文摘】使用自定义验证组件库扩展 Windows 窗体: Form Scope