最近做有关JSP与DISCUZ 整合,搞了好久,还是搞不定,后来发现下面这篇文章,呵呵.爽.?
?
作者?:See?
?
http://blog.sina.com.cn/s/blog_49298ed001000a99.html?
?
最近在实验室做项目用到的一个东西,拿来介绍一下。?
?
?
需求:现有行业应用网站一个,使用JSP开发,假设网址为app.com;及Discuz 论坛一个,使用PHP开发,假设网址为bbs.com。?现在希望将应用网站和论坛的用户进行整合,即,如果用户在应用网站已经登录,那么从应用网站点击链接进入论坛后将直接成为登录状态。?
?
Discuz 论坛提供的Passport(通行证)接口可以很好的实现上述需求。通行证可以在Discuz 论坛的系统设置中开启,开启通行证之后的论坛将不再接受除管理员以外的用户的登录请求,而与应用网站进行统一登录管理。整合之后的用户注册、登录、注销流程,请阅读参考资料[1]。下面介绍实现的整个流程,并给出关键代码。?
?
1?开发DiscuzPassport及Encryption两个类,实现与Discuz 一致的数据加密。原始代码由参考资料[2]给出,这里对其进行了一定程度的修改。?
?
-----DiscuzPassport.java-----?
?
import?java.io.UnsupportedEncodingException;?
import?java.util.Map;?
import?java.util.Iterator;?
import?java.util.Random;?
import?java.util.Set;?
import?sun.misc.BASE64Decoder;?
?
public?class?DiscuzPassport?{?
?
public?static?String?encrypt(String?src,?String?key)?{?
Random?random?=?new?Random();?
random.setSeed(System.currentTimeMillis());?
String?rand?=?""?+?random.nextInt()?%?32000;?
String?encKey?=?Encryption.generateKey(rand,?"MD5");?
?
int?ctr?=?0;?
String?tmp?=?"";?
?
for?(int?i?=?0;?i?<?src.length();?i++)?{?
ctr?=?(ctr?==?encKey.length()???0?:?ctr);?
tmp?+=?encKey.charAt(ctr);?
char?c?=?(char)?(src.charAt(i)?^?encKey.charAt(ctr));?
tmp?+=?c;?
ctr++;?
}?
String?passportKey?=?passportKey(tmp,?key);?
return?new?sun.misc.BASE64Encoder().encode(passportKey.getBytes());?
}?
?
public?static?String?decrypt(String?src,?String?key)?{?
byte[]?bytes?=?null;?
try?{?
bytes?=?new?BASE64Decoder().decodeBuffer(src);?
src?=?new?String(bytes);?
}?catch?(Exception?e)?{?
return?null;?
}?
src?=?passportKey(src,?key);?
?
String?tmp?=?"";?
for?(int?i?=?0;?i?<?src.length();?++i)?{?
char?c?=?(char)?(src.charAt(i)?^?src.charAt(++i));?
tmp?+=?c;?
}?
return?tmp;?
}?
?
public?static?String?passportKey(String?src,?String?key)?{?
String?encKey?=?Encryption.generateKey(key,?"MD5");?
?
int?ctr?=?0;?
String?tmp?=?"";?
for?(int?i?=?0;?i?<?src.length();?++i)?{?
ctr?=?(ctr?==?encKey.length()???0?:?ctr);?
char?c?=?(char)?(src.charAt(i)?^?encKey.charAt(ctr));?
tmp?+=?c;?
ctr++;?
}?
return?tmp;?
}?
?
public?static?String?passportEncode(Map?data)?{?
Set?keys?=?data.keySet();?
String?key?=?"";?
String?ret?=?"";?
Iterator?iterator?=?keys.iterator();?
while?(iterator.hasNext())?{?
key?=?(String)?iterator.next();?
try?
{?
ret?+=?key?+?"="?+?(String)?data.get(key)?+?"&";?
}?
catch?(Exception?e)?
{?
return?"";?
}?
}?
if?(ret.length()?>?0)?
return?ret.substring(0,?ret.length()?-?1);?
return?"";?
}?
}?
?
?
------------------------------?
?
?
?
?
?
-----Encryption.java-----?
?
?
import?java.io.UnsupportedEncodingException;?
import?java.security.MessageDigest;?
import?java.security.NoSuchAlgorithmException;?
?
public?class?Encryption?{?
?
public?static?String?generateKey(String?src,?String?algorithm)?{?
MessageDigest?m?=?null;?
try?
{?
m?=?MessageDigest.getInstance(algorithm);?
m.update(src.getBytes("UTF8"));?
}?
catch?(NoSuchAlgorithmException?e)?
{?
e.printStackTrace();?
}?
catch?(UnsupportedEncodingException?e)?
{?
e.printStackTrace();?
}?
byte?s[]?=?m.digest();?
String?result?=?"";?
for?(int?i?=?0;?i?<?s.length;?i++)?
{?
result?+=?Integer.toHexString(?
(0x000000FF?&?s[i])?|?0xFFFFFF00).substring(6);?
}?
?
return?result;?
?
}?
?
}?
?
?
?
------------------------------?
?
2?增加、修改几个页面,实现网站之间的整合,涉及的页面包括:?
?
index.php(Discuz 论坛首页,包含登录、注册与退出的链接)?
login_discuz.jsp(应用网站新增的登录页面)?
logined.jsp(应用网站原来的登录处理页面,这里将进行修改)?
logout.jsp(应用网站原来的注销处理页面,这里将进行修改)?
register.jsp(应用网站原来的注销处理页面,这里无需修改)?
bbsRedirect.jsp(在应用网站新增的页面,用于实现用户漫游)?
?
2.1?从论坛登录?
?
页面跳转过程为:?
index.php?->?login_discuz.jsp?->?logined.jsp?->?index.php?
?
用 户在论坛首页点击登录后,index.php将首先指向login_discuz.jsp,并以GET方式向其传递一个forward变量,用来存储登录 后跳转的目标。这里,forward一般都是论坛首页,即bbs.com。login_discuz.jsp主要负责给出用户登录界面,并以POST方式 向logined.jsp传递用户名、密码以及forward变量。?
logined.jsp负 责处理从应用网站和论坛两处提交过来的登录申请。因此,它需要首先判断上一个页面是否提交了forward变量,如果没有,那么申请就是从应用网站提交过 来的,只需按正常的流程登录(设置自身的cookie或session);如果有,那么除了按正常流程登录外,还需要对用户的登录信息进行加密,并按规定 的格式传递给index.php(这部分工作由上面两个类来完成)。?
logined.jsp中调用两个类的关键代码如下:?
?
-----logined.jsp(部分)-----?
?
<%?
String?username?=?null;?
String?email?=?null;?
String?password?=?null;?
?
//为上面三个变量赋值?
//......?
//......?
Map?mb?=?new?LinkedHashMap();?
mb.put("time",?""?+?System.currentTimeMillis());?
mb.put("username",?username);?
mb.put("password",?password);?
if(email.length()?==?0)?
{?
mb.put("email",?"null");?
}?
else?
{?
mb.put("email",?email);?
}?
?
String?key?=?privateKey;?//私钥?
String?enc=DiscuzPassport.passportEncode(mb);?
String?auth?=?DiscuzPassport.encrypt(enc,?key);?
String?verify?=?"login"?+?auth?+?request.getParameter("forward")?+?key;?
verify?=?Encryption.generateKey(verify,?"MD5");?
?
String?location?=?"http://bbs.com/api/passport.php?action=login&auth="?+?java.net.URLEncoder.encode(auth,?"UTF-8")?+?"&forward="?+?java.net.URLEncoder.encode(request.getParameter("forward"),?"UTF-8")?+?"&verify="?+?verify;?
?
response.sendRedirect(location);?
?
%>?
?
?
------------------------------?
?
?
?
2.2?从论坛注销?
?
页面跳转过程为:?
index.php?->?logout.jsp?->?index.php?
?
-----logout.jsp(部分)-----?
?
<%?
if(request.getParameter("forward")?!=?null)?
{?
String?key?=?privateKey;?//私钥?
String?verify?=?"logout"?+?request.getParameter("forward")?+?key;?
verify?=?Encryption.generateKey(verify,?"MD5");?
?
String?location?=?"http://bbs.com/api/passport.php?action=logout&"?+?"&forward="?+?java.net.URLEncoder.encode(request.getParameter("forward"),?"UTF-8")?+?"&verify="?+?verify;?
?
response.sendRedirect(location);?
}?
?
%>?
?
------------------------------?
?
2.3?从论坛注册?
?
页面跳转过程为:?
index.php?->?register.jsp?
?
2.4?用户漫游?
?
如果用户在应用网站已经登录,那么从应用网站点击链接进入论坛后将直接成为登录状态。?
假设现在用户已经完成登录,正位于JSP网站的主页index.jsp,希望通过主页上的链接进入论坛。那么页面跳转过程为:?
index.jsp?->?bbsRedirect.jsp?->?logined.jsp?->?index.php
http://blog.sina.com.cn/s/blog_49298ed001000a99.html
[1] Discuz! Passport 接口技术文档.
http://www.discuz.net/usersguide/advanced_passport.htm
[2] 一个java版的passport工具类.
http://www.discuz.net/archiver/tid-216986.html
[3] 如何基于discuz开发网站通行证的功能.
http://blog.sina.com.cn/u/563e7cc1010007os
[4] discuz论坛的passport,AzDGCrypt加密算法的java实现.
http://blog.sina.com.cn/u/401a71d10100075z