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

配置全正确还是通信失败原来是BOM的问题

修改好ucenter后台后再去修改论坛下的config.inc.php(其他应用也一样),不要使用记事本打开修改,txt保存utf8文件时会自动给文件添加 BOM,这时后台就会显示通信失败,建议使用UltraEdit编辑,保存时选择另存 “utf8 – 无BOM”

–EOF–

一般情况下,记事本在编辑和保存UTF8文件时,会自动加上BOM,但BOM虽然在文件中不显示,但在网页传输时,有3个字节的输出,因此可能会导致uc获取到的值与预想的不一致。所以,必须去掉BOM才可以。

小知识:

BOM

在UCS 编码中有一个叫做”ZERO WIDTH NO-BREAK SPACE”的字符,它的编码是FEFF。而FFFE在UCS中是不存在的字符,所以不应该出现在实际传输中。UCS规范建议我们在传输字节流前,先传输 字符”ZERO WIDTH NO-BREAK SPACE”。这样如果接收者收到FEFF,就表明这个字节流是Big-Endian的;如果收到FFFE,就表明这个字节流是Little- Endian的。因此字符”ZERO WIDTH NO-BREAK SPACE”又被称作BOM。
UTF-8不需要BOM来表明字节顺序,但可以用BOM 来表明编码方式。字符”ZERO WIDTH NO-BREAK SPACE”的UTF-8编码是EF BB BF。所以如果接收者收到以EF BB BF开头的字节流,就知道这是UTF-8编码了。
Windows就是使用BOM来标记文本文件的编码方式的。

UTF-8编码的文件中,BOM占三个字节。如果用记事本把一个文本文件另存为UTF-8编码方式的话,用UE打开这个文件,切换到十六进制编辑状态就可 以看到开头的FFFE了。这是个标识UTF-8编码文件的好办法,软件通过BOM来识别这个文件是否是UTF-8编码,很多软件还要求读入的文件必须带 BOM。可是,还是有很多软件不能识别BOM。我在研究Firefox的时候就知道,在Firefox早期的版本里,扩展是不能有BOM的,不过 Firefox 1.5以后的版本已经开始支持BOM了。现在又发现,PHP也不支持BOM。

参考:http://www.w3.org/International/questions/qa-utf8-bom

关于uc通信状态调试为1,但通信显示不成功

本文来自discuz官方论坛,由用户fangshawn发表。

最近帮网友调试uc通信不成功;经调试后发现,通信其实是成功的,但由于服务器无法确定返回的字符长度,所以采用Chunked编码动态的提供body内 容的长度;通信把编码应该出掉的部分没去除;具体调试如下;
在之前调试采用了别人的调试方法:也介绍过给网友们;就是下面这文章;
http://www.discuz.net/viewthread … &from=favorites
我的介绍就是在这基础上吧!
echo “\$url = $url <br />\n \$status = $status<br />\n”;die(‘haha’);
在上面打印status时;status返回是 110;

我尝试着找到低层代码,返回了以下结果;
HTTP/1.1 200 OK Connection: close Date: Thu, 28 Jan 2010 05:12:41 GMT Content-Type: text ml Server: Microsoft-IIS/6.0 X-Powered-By: ASP.NET X-Powered-By: PHP/5.2.9-2 Transfer-Encoding: chunked 1 1 0
也就是说 Connection 是OK;但代码接口返回结果时却不是返回我们想要的 1;而返回了110;浏览器直接调试接口时,返回的又正确是1;
最后查资料发现这个小秘密 Transfer-Encoding: chunked 1 1 0 前面的1是chunked编码后的长度;最后的0是chunked的结束符;

我尝试着在接口入口处就直接返加字母a ;结果status 变成1a0了;哈哈;

这样子在uc平台后面的通信显示是不成功的,但其实是通信是通了;会不会对同步登录造成影响我未有深入,(因为最后网友神奇的说重起了服务器就通信成功 了)
个人觉得不影响,因为同步登录是是有标签的,Chunked编码并不会改变标签;
哈哈;大家觉的呢

如果大家发因为上面的chunked编码导致同步登录不正常,留言;我会试着找出解决的方法
麻烦不找我,我也不去找麻烦;哈哈

我是曾经遇到,通信正常,但其他操作不正常,那是因为无法往应用的uc目录下写文件,还有uc_client的Cache目录。都必须要可写。因为uc的配置文件和uc_client中的Cache都会在更改应用信息的时候同步更新。

第三方整合到ucenter同步登录基本要点

这是一篇来自官方论坛的文章,大家可以在学习的同时,看看是否有什么可以借鉴的。

第三方,以下简称ot;ucenter简称uc
一、在ucenter里注册ot实用,调试通信成功(细节不表);
二、实现注册同步
1.找到ot的注册函数;用uc_get_user()验证是否用户已在注册;
(1)未注册:继续本地验证,继续第2点;
(2)已注册:检测本地用户是否注册;
[1] 已注册:提示该用户名已注册过,不允许注册;
[2] 未注册:提示该用户已注册,但未本地激活;弹出激活页面;
2.继续本地用户验证(假设成功),把用户未加密的密码用新变量保存(注册ucenter需要原始密码以保证ucenter的其它应用使用);
3.先执行ucenter注册uc_user_register;检测返回结果是否成功;
4.ucenter注册成功;获得uc_id;
5.修改本地用户注表,增加一个uc_id字段以保存注册成功返回的uc_id,实现用户的信息的关联(当然也可以用原有用户表id跟uc_id关 联,discuz就是这样处理的本地用户id)
6.把用户信息添加到本地数据库;记得保存uc_id;
三、实现ot登录,同步其他应用也登录
1.找到ot登录代码块,先采用uc_user_login登录密码验证,
2.验证成功用获得的uid跟本地的会员表id关联,查出相应信息,再发送相应本地用户cookie;
3.执行uc_user_synlogin($id);执行同步登录
四、实现共他应用登录,ot也同步登录;
1.找到ot正常登录后所要执行的cookie登录操作代码;
2.找到ot的接口:uc.php;找到synlogin 代码块,参照上一点的代码修改原接口康盛的cookie操作代码;
五、实现其他应用登出,ot也同步登出
登出跟登录的修改要点刚好相反,不细表;把原在uc.php的synlogin 注册的cookie操作执行注销就OK
六、实现ot退出,其他实用也退出;
找到ot的退出代码块,执行 uc_user_synlogout();
七、用户信息修改;
找到ot的用户修改资料代码块,缓存用户的密码(未经过加密的);在允行执行修改时先执行uc_user_edit;再执行本地用户资料修乞讨

这是我之前作的一次整合后总结;经验不足,请大家多交流发表意见

作者:fangshawn,来自http://www.discuz.net/thread-1564551-1-1.html

【官方】不小心删除了UC文件夹后的处理方法

这是一篇来自官方的教程,原帖地址为:http://www.discuz.net/thread-1477395-1-1.html

有不少用户反映,在整理空间时常常会有不小心删除掉UC文件夹的情况发生。
如果只是删除了UC文件夹,数据库里的数据还在的话,可以通过下面的方法解决:

1、拷贝一份安装好的UC的程序文件,然后修改里面的配置文件,上传到自己的空间上。

2、重新安装UC,注意安装的时候选择跟以前的UC不同的前缀,以免覆盖数据。安装完后,修改UC的配置文件,改成以前的数据的前缀。

3、在数据库中通过工具(如phpmyadmin等)备份UC数据,然后重新安装UC后,导入数据。

以上的方法只能恢复UC使用和会员的注册信息等数据,会员上传的头像等是保存在UC的data\avatar文件夹中的,删除了文件夹就不能恢复了,只能够让会员重新上传。

PS:如果连同UC的数据库一起删除掉了,而且还没有备份的话,就只能重头再来了,所以在平时的使用中一定要注意及时备份,以免丢失站点最重要的会员数据。

关于康盛UCenter整合应用的一些经验,关于同步登录的

手头上有一个PHP项目,需要和Disucz整合,使用同步登录,统一使用DZ的用户数据、短信平台等。以前也作过公用dz用户同步登录,简单的 require() Disucz的incluce/common.inc.php文件到自己的项目,就可以实现用户同步登录。但是这样的话,要实现共享用户数据、短信平台就 比较麻烦。
在康盛的网站和论坛翻了一下,发现康盛推出了UCenter这个平台,可以很方便的整合康盛旗下的各个产品及第三方应用。

根据用户说明,先安装uc,再安装dz,然后把uc安装包中的example独立出来架设一个站点。然后根据开发指南,到uc的后台中添加应用,之后应用就可以与dz共享部分数据了。

本来以为会是个很简单的规程,但是实际操作中却出现了两个难题。

一、UC后台添加应用后检查通信情况的时候出现通信失败:
这个经过排查,原来是example中的api/uc.php中要require的mysql类文件失败,
在uc.php的61行附近,有以下代码:

require_once DISCUZ_ROOT.’./include/db_’.$database.’.class.php’;

而其中的$database并未定义,导致require失败,解决的办法是在example项目的根目录下的config.inc.php中增加以下代码:
$database = ‘mysql’;

这样UC后台就会显示通信成功,至此,这个问题解决了。

二、无法同步登录、注销:
由于自己的项目是本地无用户数据的,直接调用uc的用户数据,所以以下的测试都是用ucexampe_1.php。

我遇到的情况是这样的:
在example中登陆,dz显示已登陆;在example中注销,dz同步注销;在dz中登陆,example未登录;在dz中注销,example未注销。
为了这个问题,我在dz的网站上翻了2天,并为找到任何解决的办法,其间还PM过康盛团队的人,但是并为收到任何回复。
今天下午,在dz的论坛看到一篇文章,其中有一个连接,是分析uc通信过程的,
http://hi.baidu.com/winterfog/bl … 80709d0b7b8208.html
看了这个文章后,根据文章中提到的一点,逐步debug。

1、在example的api/uc.php的 $action = $get['action']下增加以下一行代码:

echo “<pre>”;var_dump($get);echo “</pre>”;die(“<hr>api\uc.php”);

然后在dz中尝试登陆,获得dz中访问example的连接,检查输出内容,发现输出内容完全正常。

接下来继续看uc.php的代码,发现了多处读取数据库的代码,由于自己的项目在用户这一块无须读取数据库,所以暂时将uc.php中同步登录的读取数据库的部分注释掉。

根据uc.php的流程,检查synlogin函数,在这里出现了一些让人摸不早头脑的代码:

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

$this->appdir的值为example应用的物理路径,而此路径下并无forumdata目录,也就没有cache_settings.php这个问题了。不过,这个文件应该是dz目录下对应的文件。
好吧,你要require,那我就去copy过来给你。后来发现,这是多此一举,这个文件根本就不需要。

继续往下面检查,发现了很多看起来是discuz里面的变量和代码。终于看到重点了。原始代码如下:

require $this->dbconfig;
require_once $this->appdir.’./include/db_’.$database.’.class.php’;
require_once $this->appdir.’./forumdata/cache/cache_settings.php’;

$db = new dbstuff;
$this->db->connect($dbhost, $dbuser, $dbpw, $dbname, $pconnect, true, $dbcharset ? $dbcharset : $charset);
unset($dbhost, $dbuser, $dbpw, $dbname, $pconnect);
$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 {
_setcookie(‘cookietime’, $cookietime, 31536000);
_setcookie(‘loginuser’, $username, $cookietime);
_setcookie(‘activationauth’, _authcode($username, ‘ENCODE’, $discuz_auth_key), $cookietime);
}

这里的代码实现以下的功能:

连接数据库->设置cookie的过期时间->生成authcode函数所需要的auth_key->检索数据库,获得当前用户的用户名、密码、id,然后设置cookie。

之前提到过,我这个应用暂时不需要读取数据库,所以把数据库相关的代码都注释掉。只剩下以下的代码:

$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);
_setcookie(‘cookietime’, $cookietime, 31536000);
_setcookie(‘loginuser’, $username, $cookietime);
_setcookie(‘activationauth’, _authcode($username, ‘ENCODE’, $discuz_auth_key), $cookietime);

至此已经找到问题的根本了:
1、authcode所使用的auth_key本应用本身的设定不一样。应用本身设定为123456(这个在config.inc.php中设定,也就是 UC_KEY),而上面的代码是用$discuz_auth_key,直接将$discuz_auth_key更改为UC_KEY
2、authcode加密的内容有问题,ucexample_1.php判断是否同步登录使用以下的代码

if(!empty($_COOKIE['Example_auth'])) {
list($Example_uid, $Example_username) = explode(“\t”,uc_authcode($_COOKIE['Example_auth'], ‘DECODE’));
var_dump(explode(“\t”, uc_authcode($_COOKIE['Example_auth'], ‘DECODE’, UC_KEY)));
} else {
$Example_uid = $Example_username = ”;
}

通过解密cookie,获得$Example_uid和$Example_username两个变量名,而uc.php中进行加密的只有$username一个,将之修改为$uid.”\t”.$username

到此,已经解决了本地应用无用户数据库的同步登录问题。

接下来说一些感想:

1、作为康盛的关键产品UCenter,在www.discuz.net上的ucenter开发版面人气并不旺,而且管理团队和开发团队最近也很少关注关注该版面,用户提出的问题也很少得到解决的。
2、官方的开发指南错漏百出,最低级的错误是未定义$database这个非常重要的变量。
3、作为一个和dz相对独立的产品,其中的例程所使用的代码很多是照搬dz的,如果正常工作那倒没问题,但是却无法正常工作,连authcode这样关键函数所使用的auth_key居然也弄错,希望官方能仔细检查。

以上是修复uc通信与同步登录的个人的一些看法和意见,请大家多多指教。

本文来源:http://www.discuz.net/thread-1367305-1-1.html