前言
discuz_ucenter_api_for_java针对UCenter1.5/1.6版本均可正常通信,测试过程中,Discuz X2.5/X3.0/X3.2均测试通过。在开始前,有几个点需要先了解。
Discuz和UCenter是两个相对独立的应用系统,只是一般在安装Discuz的时候集成安装了UCenter。
Discuz和UCenter分别有各自独立的用户数据表,Discuz的是`数据库名`.[前缀]_common_member,Ucenter的是`数据库名`.[前缀]_ucenter_members。
UCenter是一个统一的用户管理中心,是Comsenz旗下各个产品(Discuz、X-Space、SuperSite等)之间信息直接传递的一个桥梁,通过UCenter 站长可以无缝整合Comsenz系列产品,实现用户的一站式登录以及社区其他数据的交互。
在Discuz中注册用户,Discuz会将用户同步到UCenter中。在UCenter中注册了用户,不会同步到Discuz。
搭建Discuz环境
从Discuz官网下载安装Discuz程序,安装过程略。其中数据库名和表名前缀需要记住,在后面创建Ucenter用户时同步Discuz用户时要用到。
UCenter中注册应用
UCenter登录没反应?
我遇到过这个问题,不管是Discuz X2.5还是X3,安装好Discuz后,正确输入了创使人密码,但是提交后一直没有反应,可以编辑uc_server/model/admin.php,找到约第22行的
$this->cookie_status = 0;
改成
$this->cookie_status = isset($_COOKIE['sid']) ? 1 : 0;
如果你可以正常登录UCenter,就不用管这个问题了。
从Discuz进入UCenter,在UCenter中的应用管理中添加新应用:

在添加新应用中录入以下相关参数(其它的默认,不用管):
应用类型:其它
应用名称:自定义
应用主url:Java Web应用的访问地址,http://[ip]:[port]/[appname] ,如我在本地Tomcat部署上部署了一个应用,访问地址是:http://192.168.203.128:8080/dzclient4j,注意结尾不要添加“/”(斜杠)
通信密钥:自定义,用于UCenter和Java Web程序约定的通信密钥,之后会在Java Web应用中配置同样的密钥。如“java_ucenter”
是否开启同步登录:是
是否接收通知:建议选“是”
添加成功后,会查看到刚刚添加的应用的ID,这个应用ID待会儿我们会用到。同时看到通信情况为通信失败,这个暂时不用管。

接下来,我们要将要配置我们的WEB程序,在配置WEB程序之前我们先要确认一下UCenter的地址:

因为有的地址是IP配置的,有的地址是域名配置的,所以确认一下以保证之后的配置的一致性。
配置Java Web应用
下载discuz_ucenter_api_for_java应用程序。
将src下的代码复制到本地WEB应用的src下,修改复制过来的config.properties
#UCenterf地址
UC_API = http\://192.168.203.1/bbs/uc_server
#UCenter的IP,可为空
UC_IP =
#通信秘钥,与在UCenter注册的通信秘钥一致
UC_KEY = java_ucenter
#应用ID,在UCenter注册应用生成的ID
UC_APPID = 2
#该项可为空
UC_CONNECT =
在本地WEB应用的web.xml中添加如下配置:
<servlet>
<servlet-name>api</servlet-name>
<servlet-class>com.fivestars.interfaces.bbs.api.UC</servlet-class>
<load-on-startup>2</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>api</servlet-name>
<url-pattern>/api/uc.php</url-pattern>
</servlet-mapping>
接下来,我们启动JAVA WEB应用程序,再回到UCenter的应用列表,会发现通信情况已经变成了通信成功。
登录测试
现在我们是以在discuz中可以正常登录的账号为例,账号先不要是中文的。
Client e = new Client();
String result = e.uc_user_login("test", "111111");
LinkedList<String> rs = XMLHelper.uc_unserialize(result);
if(rs.size()>0){
int $uid = Integer.parseInt(rs.get(0));
String $username = rs.get(1);
String $password = rs.get(2);
String $email = rs.get(3);
if($uid > 0) {
System.out.println("登录成功");
System.out.println($username);
System.out.println($password);
System.out.println($email);
String $ucsynlogin = e.uc_user_synlogin($uid);
System.out.println("登录成功"+$ucsynlogin);
} else if($uid == -1) {
System.out.println("用户不存在,或者被删除");
} else if($uid == -2) {
System.out.println("密码错");
} else {
System.out.println("未定义");
}
}else{
System.out.println("Login failed");
System.out.println(result);
}
如上代码,登录成功返回$ucsynlogin的是一个js,直接放到浏览器中去执行,然后,再在浏览器中打开discuz,你会发现已经登录了。
中文问题
中文问题参考http://www.cnblogs.com/gaoxing/p/4373937.html
我们来改造discuz_ucenter_api_for_java。(我的discuz和java web都是utf-8的,如果你的discuz是gbk的,则改成相应的编码来测试一下)
1.删除自带一个Base64的工具类(com.fivestars.interfaces.bbs.util.Base64),我们引用apache的commons codec包里的Base64类。修改PHPFunctions的base64_decode和base64_encode两个方法。
private Base64 base64 = new Base64();
protected String base64_decode(String input){
try {
return new String(base64.decode(input),"iso-8859-1");
} catch (Exception e) {
return e.getMessage();
}
}
protected String base64_encode(String input){
try {
return new String(base64.encode(input.getBytes("iso-8859-1")));
} catch (Exception e) {
return e.getMessage();
}
}
2.修改PHPFunctions类的urlencode方法。
protected String urlencode(String value){
try {
return URLEncoder.encode(value,"utf-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return null;
}
3.修改Client的uc_fopen方法
BufferedReader reader = new BufferedReader(new InputStreamReader(ins,"UTF-8"));
4.修改Clent的uc_authcode方法,主要是将substr($result.toString(), 26)进行转码
if($operation.equals("DECODE")) {
String $result = $result1.substring(0, $result1.length());
String temp=substr($result.toString(), 26);
try {
temp=new String(temp.getBytes("iso8859-1"),"UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
if((Integer.parseInt(substr($result.toString(), 0, 10)) == 0 || Long.parseLong(substr($result.toString(), 0, 10)) - time() > 0) && substr($result.toString(), 10, 16).equals( substr(md5(substr($result.toString(), 26)+ $keyb), 0, 16))) {
return temp;
} else {
return "";
}
} else {
return $keyc+base64_encode($result1.toString()).replaceAll("=", "");
}
注册用户
public static void testRegister(){
Client uc = new Client();
String $returns = uc.uc_user_register("王五", "111111" ,"wangwu@test.com" );
int $uid = Integer.parseInt($returns);
if($uid <= 0) {
if($uid == -1) {
System.out.print("用户名不合法");
} else if($uid == -2) {
System.out.print("包含要允许注册的词语");
} else if($uid == -3) {
System.out.print("用户名已经存在");
} else if($uid == -4) {
System.out.print("Email 格式有误");
} else if($uid == -5) {
System.out.print("Email 不允许注册");
} else if($uid == -6) {
System.out.print("该 Email 已经被注册");
} else {
System.out.print("未定义");
}
} else {
System.out.println("OK:"+$returns);
}
}
如上代码,通过Java向UCenter中注册了一个新用户。返回的$returns值是新建UCenter用户的ID。
不过我们现在只是在UCenter中注册了用户,现在直接通过Java去登录Discuz是登录失败的,需要先在Discuz页面去登录一次后,才可以从Java正常登录Discuz。这个原因主要是,我们通过Java注册用户,只是在UCenter中注册了,而并没有在Discuz中注册用户,所以第一次登录须要从Discuz登录,从Discuz登录的时候会发现没有这个用户,但是在UCenter中是认证通过的,于是便提示,是否要在Discuz中激活这个新建的用户。
好了,现在我要做的就是在注册UCenter用户的时候,也同步在Discuz中注册用户,直接在Discuz的用户表中插入数据。修改uc_server/model/user.php,大概在138行(不同版本的discuz可能有所差异),function add_user 函数里添加代码:
function add_user($username, $password, $email, $uid = 0, $questionid = '', $answer = '', $regip = '') {
$regip = empty($regip) ? $this->base->onlineip : $regip;
$salt = substr(uniqid(rand()), -6);
$password = md5(md5($password).$salt);
$sqladd = $uid ? "uid='".intval($uid)."'," : '';
$sqladd .= $questionid > 0 ? " secques='".$this->quescrypt($questionid, $answer)."'," : " secques='',";
$this->db->query("INSERT INTO ".UC_DBTABLEPRE."members SET $sqladd username='$username', password='$password', email='$email', regip='$regip', regdate='".$this->base->time."', salt='$salt'");
$uid = $this->db->insert_id();
$this->db->query("INSERT INTO ".UC_DBTABLEPRE."memberfields SET uid='$uid'");
// BEGIN
$this->db->query("INSERT INTO ".DISCUZ_DBTABLEPRE."common_member SET uid='$uid', username='$username', password='$password', email='$email', adminid='0', groupid='10', regdate='".$this->base->time."', credits='0', timeoffset='9999'");
$this->db->query("INSERT INTO ".DISCUZ_DBTABLEPRE."common_member_status SET uid='$uid', regip='$regip', lastip='$regip', lastvisit='".$this->base->time."', lastactivity='".$this->base->time."', lastpost='0', lastsendmail='0'");
$this->db->query("INSERT INTO ".DISCUZ_DBTABLEPRE."common_member_profile SET uid='$uid'");
$this->db->query("INSERT INTO ".DISCUZ_DBTABLEPRE."common_member_field_forum SET uid='$uid'");
$this->db->query("INSERT INTO ".DISCUZ_DBTABLEPRE."common_member_field_home SET uid='$uid'");
$this->db->query("INSERT INTO ".DISCUZ_DBTABLEPRE."common_member_count SET uid='$uid', extcredits1='0', extcredits2='0', extcredits3='0', extcredits4='0', extcredits5='0', extcredits6='0', extcredits7='0', extcredits8='0'");
// END
return $uid;
}
注意这些表都是 Discuz 的表,不是 UCenter 的表,不能使用 UC_DBTABLEPRE ! UCenter 配置文件 uc_server/data/config.inc.php 中定义了 DISCUZ_DBTABLEPRE:
define('DISCUZ_DBTABLEPRE', '`bbs`.pre_');
bbs是数据库名称,pre是安装discuz时指定的前缀。
同步退出
public static void testLogout(){
Client uc = new Client();
String $ucsynlogout = uc.uc_user_synlogout();
System.out.println("退出成功"+$ucsynlogout);
}
既出的代码很简单,类似于同步登录,返回的$ucsynlogout也是一个javascript脚本,交由浏览器来处理。
参考:
http://my.oschina.net/u/1274710/blog/165570
http://my.oschina.net/banbo/blog/311691
来源:oschina
链接:https://my.oschina.net/u/227671/blog/550353