UCenter 与 Asp.net 通讯

原文来自于:http://www.cnblogs.com/dozer/archive/2010/09/21/ucenter-api_with_asp-net.html,作者:Dozer。

因为我一直是在做PHP版的通讯,因此有asp.net的也就贴出来,相信可以给更多人帮助。

前言

学生在线下面有多个子站,其中包括一个Discuz论坛
那当然要充分利用强大的UCenter来实现多点登陆
UCenter和别的网站跨域通讯,那用的肯定是WebService
PHP官方封装好了,所以很容易就搞定了,但是.Net…
网上找不到任何核心的通讯手册,除非去扣那个PHP的开发手册
Google后:
UCenter 接口开发手册:这个就是官方封装过的版本,其实这个根本不能叫接口开发手册,里面介绍的都是已经封装过的PHP函数,对核心只字不提
一个项目文件:刚看到这个我很兴奋,但是按照它说的调整好后,却不能用!一开始还不懂为什么,懂得原理后才知道,它其实是个空壳
一个DLL文件:这个DLL很强大,可惜,没有例程、没有手册、没有注释,还有BUG…
但是相对来说,最后的那个DLL是最接近的,所以决定反编译之,开始研究
最后就有了Dozer编辑版~ 成功实现通讯!

UCenter通讯原理

原理网上很多,我也只是知道一个皮毛,在这里就以同步登陆为例子,来讲解一下这个类库的用法

以上就是同步登陆的步骤,如果你已经配置好,那么只需要这3行代码

namespace WebApplication1
{
    public partial class Default : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            var uc = new UCClient();
            var user = uc.UC_User_Login("user", "password").User;
            Response.Write(uc.UC_User_Synlogin(user.Uid));
        }
    }
}

总之,在你的网站程序中需要有2个部分
一个是UCAPI部分,需要给UCenter调用
另外一部分就是UClient部分,用于调用UCenter
这样才能在最后实现双向通讯

UCenter端配置过程

按照惯例,登陆UCenter后台,然后添加应用程序
别的地方和PHP网站一样,只有一个地方,就是“应用接口文件名称”的地方
需要填写uc.ashx
这个和此类库的原理有关,后面详解

提交…可惜,显示通讯不成功,因为我的网站还没配置呢~
提交后再次编辑,会得到一段PHP的配置信息

define('UC_CONNECT', 'mysql');
define('UC_DBHOST', localhost');
define('UC_DBUSER', 'root');
define('UC_DBPW', 'mysql');
define('UC_DBNAME', 'uc_discuz');
define('UC_DBCHARSET', 'utf8');
define('UC_DBTABLEPRE', '`uc_discuz`.uc_');
define('UC_DBCONNECT', '0');
define('UC_KEY', 'qwertyui');
define('UC_API', 'http://localhost/ucenter');
define('UC_CHARSET', 'utf-8');
define('UC_IP', '127.0.0.1');
define('UC_APPID', '19');
define('UC_PPP', '20');

先留着,后面会用到~

WebApplication端配置过程

第一步当然是Web.config文件

新建一个网站应用程序,并且引用这个类库
上面的配置信息是PHP用的,我们把它转换到Web.config文件中去

<appSettings>
 <add key="UC_CONNECT" value="mysql"/>
 <add key="UC_DBHOST" value="localhost"/>
 <add key="UC_DBUSER" value="root"/>
 <add key="UC_DBPW" value="mysql"/>
 <add key="UC_DBNAME" value="uc_discuz"/>
 <add key="UC_DBCHARSET" value="utf8"/>
 <add key="UC_APPIDUC_DBTABLEPRE" value="`uc_discuz`.uc_"/>
 <add key="UC_DBCONNECT" value="0"/>
 <add key="UC_KEY" value="qwertyui"/>
 <add key="UC_API" value="http://localhost/ucenter"/>
 <add key="UC_CHARSET" value="utf-8"/>
 <add key="UC_IP" value="127.0.0.1"/>
 <add key="UC_APPID" value="19"/>
 <add key="UC_PPP" value="20"/>
</appSettings>

第二步是建立UCAPI,供UCenter调用(这步完成后UCenter中会显示通讯正常)

1、新建一个叫API的文件
2、在里面建立一个新文件uc.ashx(不要建立.aspx)
3、打开这个uc.ashx文件,本来它继承于IHttpHandler,我们把它修改一下,让它继承于FS.API.UCenter.UCAPI.UCAPIBase
4、实现一下这个抽象类的函数(利用VS的代码自动完成功能)
5、接下来你就可以在这里写一些逻辑代码了
比如,当有人在别的站同步登陆后,会通知你的站点
然后会调用 Synlogin 函数,这时候,你就需要在这个函数里写一些代码
例如:写cookie之类的
Q:UCenter为什么不直接写Cookie,子站读Cookie?
A:UCenter实现的是跨域登陆,所以每个子站的Cookie是分开的,需要自己实现!
好了,完成这步后打开UCenter,你会发现:通讯成功!
UCenter测试通讯成功仅仅是调用了一个test函数,只要上述配置没写错,那就会显示通讯成功!但是它还不能实现任何功能,需要把上面的那些函数完善~

第三步是在网站中调用UCenter的接口了

这个超级简单,其实“UCenter通讯原理”那部分代码
为什么要Respon.Write这段东西?
这和UCenter同步登陆原理有关,向UCenter传递信息,告诉它要同步登陆后,它不会自己通知别的子站,而是返回一段JS,需要你的网站调用这段JS,然后通知各个子站
OK了~所有配置完成~

我对原来的那个DLL做了什么?

1、原来的DLL编码部分有几个严重的问题,导致编码错误,无法提交表单
2、原来的DLL估计是很久以前写的,里面序列化和反序列化的时候,规则和现在UCenter的规则不同,我根据现在的规则,修改了一下
3、修复别的一些小BUG

类库下载&示例代码

代码的原始作者找不到了,遵循开源精神
另外不保证目前代码全部正确,我只是测试了几个函数
类库源代码:下载
示例代码:下载
原文来自于:http://www.cnblogs.com/dozer/archive/2010/09/21/ucenter-api_with_asp-net.html,作者:Dozer

在其他系统注册用户后,如何到discuz的时候自动激活

其实任何一个系统都一样,在A系统注册后,如何到B系统自动激活?其实很方便,修改一下每一个系统的uc.php中的synlogin方法即可,我这里以discuz 7为例写了一个简单的(我没有判断uid无效的情况,实际应用中需注意,但其实问题也不大,因为返回的值被你自己插入后也全是空,如果为了严谨,还是加上一个判断较好)

function synlogin($get, $post) {
$uid = $get['uid'];
$username = $get['username'];
if(!API_SYNLOGIN) {
return API_RETURN_FORBIDDEN;
}

require_once $this->appdir.’./forumdata/cache/cache_settings.php’;

$cookietime = 2592000;
$discuz_auth_key = md5($_DCACHE['settings']['authkey'].$_SERVER['HTTP_USER_AGENT']);
header(‘P3P: CP=”CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR”‘);
$uid = intval($uid);
$query = $this->db->query(“SELECT username, uid, password, secques FROM “.$this->tablepre.”members WHERE uid=’$uid’”);
if($member = $this->db->fetch_array($query)) {
_setcookie(‘sid’, ”, -86400 * 365);
_setcookie(‘cookietime’, $cookietime, 31536000);
_setcookie(‘auth’, _authcode(“$member[password]\t$member[secques]\t$member[uid]“, ‘ENCODE’, $discuz_auth_key), $cookietime);
} else {
require_once $this->appdir.’./uc_client/client.php’;

list($tmp['uid'], $tmp['username'], $tmp['email']) = uc_get_user($uid,1);
$password = md5(time());
$onlineip = $_SERVER['REMOTE_ADDR'];
$timestamp = time();
$secques = ”;
$this->db->query(“INSERT INTO “.$this->tablepre.”members (uid, username, password, secques, adminid, groupid, regip, regdate, lastvisit, lastactivity, posts, credits, email, showemail, timeoffset, pmsound, invisible, newsletter) VALUES (‘$uid’, ‘$username’, ‘$password’, ”, ’0′, ’10′, ‘$onlineip’, ‘$timestamp’, ‘$timestamp’, ‘$timestamp’, ’0′, ’0′, ‘”.$tmp['email'].”‘, ’0′, ’9999′, ’1′, ’0′, ’1′)”);
$this->db->query(“REPLACE INTO “.$this->tablepre.”memberfields (uid) VALUES (‘$uid’)”);
_setcookie(‘sid’, ”, -86400 * 365);
_setcookie(‘cookietime’, $cookietime, 31536000);
_setcookie(‘auth’, _authcode(“$password\t$secques\t$uid”, ‘ENCODE’, $discuz_auth_key), $cookietime);
}
}

这其中有几个需要注意一下,新用户在discuz中涉及到两个表:member和memberfield。然后member的表字段,请尽量与我上面写的一致,否则有可能还需要让你手工激活。(至于为什么,我忘了,这是一年前的代码了。)

Ucenter API通讯失败常见可能

一般来说正常情况下,在ucenter管理中心可以对于应用管理可以查看通讯是否成功。其实很正常,遇到这种问题大多有以下几种原因:

1、uc_client目录下有一个cache目录,是否可写?通讯成功后应该会把所有的应用的信息全部存入一个cache文件的。如果不可写,可能会出错【这个情况应该是在调用updateapps方法的时候才会出现】

2、检查一下,是否有那种define定义的变量没有设置而在uc.php中存在,如果直接access dined的话,也会通讯失败,因为返回的结果不是1。

3、检查一下程序代码是否错误,这也是通讯可能失败的原因,比如方法不存在,但是方法的调用是在if判断中,正常情况下,if判断可能用不到这个函数,因此检查起来就比较繁琐。

以上是我的一点小看法,也被人误会过。http://www.discuz.net/redirect.php?goto=findpost&ptid=1606517&pid=13611356,在这里,就被人误会成了我是在骗点击。唉。真可悲

[来自官方论坛]Ucenter与wordpress整合

纯转载,来源地址为:http://www.discuz.net/thread-1359599-1-3.html,由于文章内部转载的地止已经无法打开,故仅留官方论坛的地址了

1.首先并在ucenter中添加应用,其中通信密钥随便输入,复制下来。
2.在wordpress目录中放一个uc_client文件夹,这个文件夹可以从ucenter相关的包中得到,是所有客户应用都会用到的。
3.更改wordpress配置文件wp-config.php,在其中加类似如下代码(请自行修改加粗部分):
//added by afo…
//登录和退出时发出通知
define(’UC_CONNECT’, ‘mysql’); // 连接 UCenter 的方式
define(’UC_DBHOST’, ‘localhost’); // UCenter 数据库主机
define(’UC_DBUSER’, ‘wpdb_f’); // UCenter 数据库用户名
define(’UC_DBPW’, ‘1fdsf2_=’); // UCenter 数据库密码
define(’UC_DBNAME’, ‘wpdb’); // UCenter 数据库名称
define(’UC_DBCHARSET’, ‘utf8′); // UCenter 数据库字符集
define(’UC_DBTABLEPRE’, ‘wpdb.uc_’); // UCenter 数据表前缀
define(’UC_DBCONNECT’, ‘1′); // UCenter 数据库持久连接
define(’UC_KEY’, ‘fksal43dfssdfwerfdssafsafsafsafdsaf’); // 与 UCenter 的通信密钥
define(’UC_API’, ‘http://blog.treeber.com/ucenter’); // UCenter URL
define(’UC_CHARSET’, ‘utf-8′); // UCenter 的字符集
define(’UC_IP’, ”); // UCenter 的 IP
define(’UC_APPID’, 3); // 当前应用的 ID
define(’S_ROOT’, substr(dirname(__FILE__), 0));
define(’UC_CLIENT_ROOT’, S_ROOT.’/uc_client/’);
include_once(UC_CLIENT_ROOT.’client.php’);
将下面的api文件解成api目录后放在wordpress目录下,然后调试下确保从ucenter中可以与wordpress正常通信。
api for wordpress
4.需在index.php中第一行,即
define(’WP_USE_THEMES’, true);
前添
ini_set(’output_buffering’, ‘On’);
5.找到这个文件:
wp-includes/pluggable.php中,搜function logout(),约468行,在}即函数结束前添如下代码
//added by afo…
//加uc登出通知
uc_dsetcookie(’auth’, ”);
echo uc_user_synlogout();
exit();
在其下(即}之后,endif;之前)添加一个函数,代码如下
function uc_dsetcookie($var, $value, $life = 0, $prefix = 1) {
global $cookiedomain, $cookiepath, $_SERVER;
setcookie($var, $value, $life ? time() + $life : 0, $cookiepath,$cookiedomain, $_SERVER['SERVER_PORT'] == 443 ? 1 : 0);
}
6.找到这个文件:
user.php文件中
搜function wp_signon,在下面的return前(约59行)加
//added by afo…
echo uc_user_synlogin($user->ID);
Author: kolidon

当心uc_feed_get函数的第二参数

discuz的几乎所有程序都有一个:加入事件,那么,其他平台怎么获取这个事件呢?那就是uc_feed_get方法了。但 事实上,有很多人都没有注意过这个方法有第二个参数。

如果你直接去uc的uc_feed表查看,你会经常性的发现这个表是空的。而autoIndex却很大,这又是为什么呢?

于是打开uc_client方法,却发现这个函数有两个参数,第一个参数是一次获取的条数,第二个参数是Delete,默认值为true,也就是说,获取完多少条后,他都会自动删除。因此uc_feed表就几乎是永远空着了。

但问题也就在这里。我怎么知道是哪个系统获取了这些feed呢?A系统获取Feed后,B是不是也获取到了呢。又怎么处理的呢?没有仔细看代码。。。

文档中uc_feed_get只提供了一个参数limit,可以查看:http://www.ucapi.com/api/feed.htm

建议在开发的时候,先找一个uc_feed_get方法。自己写程序处理。否则,应该会出现a系统有Feed,B系统没有Feed的情况。【慎重,主要还是没有队列。。。或者推送机制,否则在有了feed后,同步向各个系统推送一下Feed呢?不就结束了?】

uchome的UC接口中有一个addfeed方法,理论上是应该在其他系统添加后往uc.php推送的。只是没有看到哪里有推送代码。。。难道是放在事件中?迷惘了。

ThinkSNS与Ucenter整合

上回我写过一点thinksns与ucenter整合的注意事项,详情可见:thinksns在整合Ucenter的时候注意事项,今天我写的另外的一些注意点。

上回仅仅是做UCAPI接口的通讯以及同步登录和退出,因此完全没有涉及到系统模块。今天我要讲的是,如何修改系统自带的login,logout,register,changepwd以及后台的管理。

如果你将login,logout,register都交由第三方来托管,那么,本文的前几段你几乎可以忽略掉。仅看最后的changepwd以及后台管理的注意事项。

OK,让我们开始吧。判断是否登录,我这里不管了,请看我上篇文章吧。。

【注意】由于加载uc_client,会导到错误发生,原因查看:THINKPHP框架与Ucenter通讯注意事项,因此,我在thinksns的define.inc.php中,强行定义了uc_connect为空,这是一个常量,在这里定义后,在uc_config文件中又定义了一次。会出现一个notice,这个我们不用管。常量是不会被覆盖的。之所以这样做,我是有理由的。thinksns在整合Ucenter的时候注意事项一文中我说过,uc.php没有用到任何thinkSNS除api外的核心函数,因此也就没有加载THINKPHP框架,所以不会有THINKPHP框架与Ucenter通讯注意事项文中所说的base类的冲突。而我们现在涉及的则是在thinksns内部使用uc_client,那就不得不先定义uc_connect模式了。正是基于常量不会被覆盖,所以uc_config文件,就不需要被修改了。【方法有点野蛮,但我想应该可以接受】

1、login,系统的login和dologin函数都在IndexAction.class.php中,因此,改起来比较方便,但是需要动/public/themes/中的apps.html模版,因为登录框在这个文件中。没办法,不改不行,uc不支持email登录,所以不得不把email改为username。然后在dologin方法中,直接调用接口,判断用户是否存在,如果不存在则返回错误,存在的话就登录。登录时还要判断,如果该用户在thinksns库中没有记录,则生成一条记录,用户信息由uc_get_user取回来。同时设定active为1,代表是已激活用户。然后就是原始的登录流程,生成session生成cookie之类的了

2、logout,除了系统标准的logout外,还需要调用一下uc_user_synlogout,以便向其他应用发向退出系统的请求

3、register,如果属于偷懒情况,你可以把register引用到别的应用中【我是自己定义了一个user应用来接管所有的,注册、登录、退出的,所以1、2这些问题,其实我都可以忽略掉】

4、changepwd,这是在用户信息管理界面中的。主要问题也就在这里。如果你不改程序,那你会在这里吐血,因为如果你的用户是通过ucenter过来的,那么password并非标准的md5(password),它的password是有salt的【salt你可以看一下ucenter表。不想多解释】,因此chagepwd功能,你必须得完全改掉。判断原始密码是否正确,也必须先用uc_get_user获取用户的信息后,把获取回来的密码与提交过来的原始密码比对。更改密码时也需要用uc_user_edit进行修改【其实可以两步并一步,因为uc_user_edit的第二个参数就是oldpassword,如果oldpassword不正确,会返回错误代码的,也可以少做一步】,更改完后,就是一个比较重要的一步:把你刚才设置的newpassword,重写回thinksns数据库,可能你会认为是多余的,因为很明显,我们前面的操作都是直接读写ucenter的用户资料,根本没有涉及到本地thinksns用户数据库,为什么还要写回密码?这其实是因为下面的第5步

5、管理,如果你是新安装thinksns,那么或许你不会遇到我说的问题,但如果你是已经安装好,而迁移过来的thinksns,你会发现,你永远登录不了管理界面,为啥?因为你登录前台时的密码是发给ucenter的,而登录后台时,密码是thinksns本地的。因此,你必须得通过changepwd功能先修改一下密码,然后才能操作【所幸管理员不多,这样的问题也都还能够被接受。】

好了,写了这么多,也很累了。如果你遇到问题,也可以咨询我,或者在这里留言。希望本文能够给你带来帮助。

本文首发在这里,明后天会转到我自己的勃客上去,我的勃客地址为:http://www.neatstudio.com,或者你也可以通过http://www.neatcn.com进行访问。

THINKPHP框架与Ucenter通讯注意事项

这其实是一个老问题,凡是使用ThinkPHP与Ucenter通讯的程序都需要注意一点。。

ThinkPHP定义了一个基类为Base类,而Ucenter也同样定义了一个基类Base类。
ThinkPHP一开始就加载了BASE类,而Ucenter在使用mysql连接的的时候,就会加载BAse类。因此,凡是使用thinkphp的程序,请把ucenter的连接方式从mysql改为空,即,改用post方式通信 。

Over

其实,关于这个BUG,我很早就在discuz论坛提过了。当然也在ThinkPHP论坛提过。但事实上,都没有什么解决方案。而我更推崇的应该是ucenter进行变化。。呵呵

thinksns在整合Ucenter的时候注意事项

thinksns在整合ucenter的时候难度并不大。主要有几个思路,不要错过就行了

1、不要想着把thinkphp框架整合进去,那样只会让你效率大低
2、合理应用thinksns提供的API,在API里面有取得当前登录用户的资料等信息,而且也有一个比较完整的数据库操作类【主要是不需要再调用config等配置了】

3、利用ucenter整合的时候,只能利用thinksns的一个cookie: remembor【开始为了这个我折腾了半天,我一直都打成remember。。。。汗一下先】(由于现在我是在一台机器上试,对于$_SERVER['USER_AGENT']是否一致还没有完全测试。。。)

4、整合的两个重要环节就是同步登录和退出。登录的时候要注意一下,两边的密码机制不一样,第一次同步资料的时候需要注意一下,否则一旦整合就不能使用原来的密码了。

5、同步登录的时候,如果需要强制注册,则必须要调用$api->user_add($data)这样的方法,具体的变量参数可以参考 thinksns的lib中的indexAction.class.php ,顺便说一下,它的代码,注册中的隐私,其实没有插数据库。。。。骗子啊

6、起初的时候,我考虑需要读系统配置,就调用了$api->option_get()结果出错,由于ucenter api的出错是不显示的。调试了半天,才发现。原来是option_get()调用的get方法中,居然有一个ts_cache函数,而这个函数却是在 api的范围之外,即它是属于thinksns的common方法中,在api中并没有被包含进来。。导致无法执行出错。

其他就没啥了。。至于feed同步啥的,则需要一点点的测试和更新,以同步到thinksns的feed库中。是个劳心劳力的过程。

首发:http://www.neatstudio.com

UCenter与其他语言的整合经验归纳

1、UCenter建议使用GBK版本,原因是PHP4/5对UNICODE(UTF-8)的支持不足,分解出来的数字与其他支持UNICODE的语言不同,以至于authcode的时候将出现偏差,非拉丁文本将不匹配,即导致中文用户名无法正常同步。但其他语言的API可以使用UTF-8,再在 authcode之前将文本转换成GBK即可。

2、Java下有一个UCenter的API,可以较方便的在Java环境下调用UCenter接口,地址是 http://code.google.com/p/discuz-ucenter-api-for-java/,创始人是ping.china。 Snow_Young也有重新开发一个API的想法,以更符合Java的开发习惯,同时希望可以找到途径以解决UTF-8的问题。

3、登入、登出等操作的同步,使用post方式调用UCenter的API接口,如果成功,将返回一段代码,其代码输出到页面将达到跨域请求各应用,应用获得请求后自行进行cookie或session的操作。

4、注册等非同步操作,将不会自动进行同步操作,其他应用在调用数据前应先检查UCenter时候存在更新信息,并将更新信息同步到自身数据库中。例如注册操作,如果用户在例如Java端注册,那么Java端将告诉UCenter注册信息,UCenter将信息存入UCenter数据库中,此时将不进行同步。之后若用户在Discuz!论坛登陆,Discuz!首先将查看自身数据库,若没有,再去请求UCenter获得更新信息,并询问用户是否激活,待用户确认后,才将用户的资料写入Discuz!论坛数据库中。

5、关于UCenter的接口,请下载或直接在线访问Discuz!论坛UCenter开发区置顶帖的API文档。

6、UCenter API文档中函数的调用方法:

integer uc_user_register(string username , string password , string email [, integer questionid , string answer])

以此为例,将函数名分解为user和register,我们可以调用UCenter的index.php,post内容为:

m : user
a : register
release : 1.5
inajax : 1(此参数若不存在,将出现一个跳转div,仅限PHP,所以在此处随意赋上一个值即可)
appid : 3(此为其他语言应用在UCenter中的id)
input : 将所有附加参数的键值对Map经过authcode之后得到的加密字符串

调用完后,此函数将返回注册信息(是否成功、错误原因)的数字。然后我们这里switch一下后采取各种策略。

7、不知是否是bug,或者是特意设计成这样的,Discuz!新注册用户会自动登陆,但却不会进行同步,即不通知其他应用,我建议还是通知一下比较好,呵呵,至少我的应用是这么做的,用户在我这里注册,然后转到Discuz!后,已经进入待激活状态,非常方便。

maxInteger、暂时总结这么多,日后发现还会继续补充,希望大家可以共同完善。

来源:http://sny7.javaeye.com/blog/484502

【官方】UC备份时出现“无法访问到该应用的备份接口”错误的解决方法

在UC后台进行备份时,经常有人会遇到下面的问题:
备份提示:无法访问到该应用的备份接口,请拷贝 UCenter 根目录下api/dbbak.php 到该应用的api目录下

这种情况有两种解决办法:
一、按照错误提示,把UCenter 目录下的 api/dbbak.php 拷贝到备份出现错误的应用中,相应的 api 目录下

二、如果(一)的方法不好用,请检查一下程序的安装端口是否为80端口,如果是非80端口,也有可能会出现上述问题
此时的解决方法是:
找到UCenter目录下的model/misc.php
把其中两处的

$out .= “Host: $host\r\n”;

改成

$out .= “Host:$host:$port\r\n”;

然后再重新备份。

本文来自官方:http://www.discuz.net/thread-1384475-1-1.html