最近在做一个ASP.NET的系统,需要与Discuz整合实现双向登录、注册、修改密码这些简单的集成。
查了一些资料,最后还是选择了官方提供的DiscuzToolkit,由于是开源的,所以用起来也方便,可以根据自己的需求做一些调整,在此也感谢DZ团队。
第一步,当然还是将论坛安装好,调试好,一切正常。
第二步,学习官方提供API文档,http://nt.discuz.net/showtopic-66493.aspx。
第三步,查看官方提供的示例文档,http://nt.discuz.net/showtopic-81187.aspx。
第四步,项目中引入Discuz.Toolkit.dll(可直接将开源的项目添加到项目中)在网站中增加同步登录或注册BBS帐号的方法,登录后或注册完成时,如下:
//......登录代码,登录成功后。 //将登录信息同步论坛,若没有此会员则 注册 try { DiscuzSession ds = DiscuzSessionHelper.GetSession(); Discuz.Toolkit.User user = null; try { user = ds.GetLoggedInUser().GetUserInfo(); } catch { } if (user == null || user.UserName != _user.UserName) { int uid = ds.GetUserID(_user.UserName); if (uid < 1) { //注册新用户 uid = ds.Register(_user.UserName, password, _user.Email, true); //填充基本信息 UserForEditing ufe = new UserForEditing(); ufe.RealName = _user.ActualName; ufe.IdCard = _user.IdCard; ufe.Mobile = _user.Phone; ufe.Phone = _user.Tel; ufe.Gender = _user.Gender.ToString(); ufe.NickName = _user.ActualName; ufe.GroupId = 10;//会员等级,可能采用特殊组来做一些其它应用。 ds.SetUserInfo(uid, ufe); } //同步登录 ds.Login(uid, password, true, 0, ""); } } catch (Exception ex) { LogHelper.WriteLog(ex); //错误日志 }
注册或修改密码对应的方法中,同步方法如下:
DiscuzSession ds = DiscuzSessionHelper.GetSession(); int uid = 0; try { //user = ds.GetLoggedInUser().GetUserInfo(); uid = ds.GetUserID(oldm.UserName); if (uid > 0) { //TODO:Discuz.Web.Services.Actions.Users 与 Discuz.Toolkit.User要对应起来 UserForEditing也一样 //填充基本信息 UserForEditing ufe = new UserForEditing(); ufe.RealName = model.ActualName; ufe.IdCard = model.IdCard; ufe.Mobile = model.Phone; ufe.Phone = model.Tel; ufe.Gender = model.Gender.HasValue ? model.Gender.ToString() : "0"; ufe.NickName = model.ActualName; ufe.Password = model.Password; ufe.GroupId = model.Level.Value + 16; ufe.UserName = model.UserName; ufe.Email = model.Email; ufe.WebSite = ""; ufe.Location = ""; ds.SetUserInfo(uid, ufe); } } catch(Exception ex) { LogHelper.WriteLog(ex); }
以上GroupId、UserName属性,在官方提供的开源项目UserForEditing类中没有这两个属性,我们可以手动加入一下,同时要注意Discuz.Web.Services.Actions.Users 与 Discuz.Toolkit.User要对应起来 UserForEditing也一样,如下:
//Discuz.Web.Services.API下UserForEditing类中增加: [JsonPropertyAttribute("group_id")] public int? GroupId; //用户组ID [JsonPropertyAttribute("user_name")] public string UserName; //用户名 //Discuz.Web.Services.API.Actions下Users类的SetInfo()方法中增加: //组别 if (ufe.GroupId.HasValue) { userinfo.Groupid = ufe.GroupId.Value; } //用户名 if (ufe.UserName != null && ufe.UserName!="") { userinfo.Username = ufe.UserName; }
如果Services中与前面调用的类属性不一致的话,会出现序列化异常。
至此,我们已经实现了网站到论坛的同步登录、注册、修改基本信息功能。
接下来就是实现,论坛到网站的同步登录、注册、修改了,在这里仅以登录为例,其它都差不多。
在这部分,我们就要使用官方提供的API操作了。
第一步,需要在后台“扩展” - “整合设置” 那里加上调用URL,如图:
上面,同步数据的URL地址为网站中的一个处理页面,主要就是在这个页面里实现同步操作。
第二上,了解参数类型,DZ的同步机制是,在论坛有登录、注册等动作操作后,通过javascript脚本,向指定的URL地址传递参数的方式实现通信,参数的基本格式为uid=1&user_name=test&time=1270283913981&action=login&sig=dskljoiwjelkjskdjfoiwelkjsifs。可以在官方提供的API说明中了解这些参数的作用,特别是sig的生成。
第三步,了解Discuz.Forum.Sync类中各种action的值及参数,方便在网站的api页面中处理。
接下来,我们来实现登录同步,如下:
private DiscuzSession ds; private string action = "", user_name, password; private int uid = 0; protected void Page_Load(object sender, EventArgs e) { try { ds = DiscuzSessionHelper.GetSession(); if (!IsPostBack) { action = Handler.RequestQueryString("action"); uid = Handler.RequestQueryInt("uid"); user_name = Handler.RequestQueryString("user_name"); password = Handler.RequestQueryString("password"); if (action != "" && check_sig()) //验证sig是否合法 { switch (action) { case "login": //同步登录:uid,user_name,time,action 正序后 + secret(密钥) Md5后 算出sig Login(); break; case "logout": //同步退出 LoginOut(); break; case "updatepwd": //同步修改密码 break; } } } } catch (Exception ex) { LogHelper.WriteLog(ex); } } /// <summary> /// 登录 /// </summary> private void Login() { Discuz.Toolkit.User user= ds.GetUserInfo(uid); if (user != null) MemberOp.ValidateLogin(user.UserName, user.Password, true); } /// <summary> /// 退出 /// </summary> private void LoginOut() { MemberOp.LoginOut(false); }
以上check_sig()方法里,主要就是验证sig是否正确,这个值是通过参数排序后md5出来的,具体过程可以参考方法:Discuz.Forum.Sync.GetUrl()。
注意密钥apikey、secret、url这几个值一定要配置正确。至此已实现论坛到网站的同步登录和退出。
DiscuzToolkit线程同步,相信这两个问题肯定会碰到:
(1)在注册用户时,碰到以下异常:当前会话所提交的call_id没有大于前一次的call_id
(2)注册用户时,碰到以下异常:An item with the same key has already been added.
解决办法:http://www.cnblogs.com/baihmpgy/archive/2012/04/09/2438720.html
解决方案中,有一处线程锁的问题:
lock (_syncRoot) 可直接用 lock (this)