discuz无疑是目前市面上最好的论坛之一,对于大多数公司来说,用discuz搭建一个论坛肯定是最节约成本的选择,然而我们的会员想要和discuz进行整合的话,只有两种荀泽,一种直接选用discuz的数据库的用户表作为自己系统的用户表(这种不现实,我如果是mssql,或者是oricle怎么办呢?),第二种就是使用discuz为了解决大家这中需求而提出的ucenter技术,目前小米论坛就是采用的这种技术,下面我就为大家介绍一下.net下使用ucenter的注意细节。

首先引入的第三方已经开发好的ucenter sdk,其原理在其主页文章http://www.dozer.cc/2011/01/ucenter-api-in-depth-1st/

下面我介绍在nopcommerce中使用ucenter的步奏

第一步:你要得到和UCenter进行通信的类库,作者的主页有原始类库http://www.dozer.cc/2011/05/ucenter-api-for-net-on-codeplex/,是asp.net 4.0版的。

第二步,你在你的asp.net项目中引用该类库,引用类库的时候,Browse到dll就行,没有必要把整个项目原代码添加到你的解决方案中。
这个类库有两个重点的文件夹需要注意:DS.Web.UCenter.Api与DS.Web.UCenter.Client,
其中DS.Web.UCenter.Api用于响应由UCenter中心发出的通知消息;
然后DS.Web.UCenter.Client用于本地向UCenter发送消息;

第三步,你需要一个响应通知的页面了,这里为了尊重原作者,我们相应地址的倒数第二层一定要是api,所以我们可以注册一个路由,让该路由的倒数第二层为api

 protected override void RegisterPluginRoutes(RouteCollection routes)
{
RegisterPluginRoutesAdmin(routes, "UCenter"); routes.MapRoute("apiuc",
"api/uc",
new { controller = "UCenterOpenApi", action = "OpenApi" },
new[] { Constants.ControllersNamespace }); }

这样子我们就可以通过 http://localhost:305/api/uc 访问到指定控制器下的方法了,

接下来我们就要写UCenterOpenApiController控制器下的OpenApi方法了,代码如下

 public UCenterOpenApiController(UcApiService ucApiService,
HttpSessionStateBase httpSession,
UCenterSetting uCenterSetting)
{
this._ucApiService = ucApiService;
this._httpSession = httpSession;
this._uCenterSetting = uCenterSetting;
} public ActionResult OpenApi() {
_ucApiService.ProcessRequest(System.Web.HttpContext.Current);
return Content("");
}

这段代码的意思就是依赖注入 UcApiService服务,调用UcApiService的PR方法,我想聪明的你一定猜到UcApiService一定是继承了.net中的IHttpHandler接口才能条用PR方法的对吧,

没错,你猜的很正确,下面看一下UcApiService的代码

  public class UcApiService : UcApiBase
{
#region Fields
/// <summary>
/// 认证服务
/// </summary>
private IAuthenticationService _authenticationService; //....字段略 #region 同步登陆
/// <summary>
/// 同步登陆
/// </summary>
/// <param name="uid">uid</param>
/// <returns>ApiReturn</returns>
public override ApiReturn SynLogin(int uid)
{
//IUcClient client = new UcClient();
var user = _uclient.UserInfo(uid);
if (user != null && user.Success)
{
Customer customer = GetNopCustomer(user);
if (customer != null)
_authenticationService.SignIn(customer, true);
else
{
customer = new Customer
{
CustomerGuid = Guid.NewGuid(),
Email = user.Mail,
Username = user.UserName,
Password = new Random().Next().ToString(),
VendorId = ,
Active = true,
CreatedOnUtc = DateTime.UtcNow,
LastActivityDateUtc = DateTime.UtcNow,
};
_customerService.InsertCustomer(customer);
//角色
_genericAttributeService.SaveAttribute(customer, SystemCustomerAttributeNames.FirstName, user.UserName);
//add to 'Registered' role
var registeredRole = _customerService.GetCustomerRoleBySystemName(SystemCustomerRoleNames.Registered);
if (registeredRole == null)
throw new NopException("'Registered' role could not be loaded");
customer.CustomerRoles.Add(registeredRole); //Add reward points for customer registration (if enabled)
if (_rewardPointsSettings.Enabled &&
_rewardPointsSettings.PointsForRegistration > )
customer.AddRewardPointsHistoryEntry(_rewardPointsSettings.PointsForRegistration, _localizationService.GetResource("RewardPoints.Message.EarnedForRegistration")); _customerService.UpdateCustomer(customer);
_authenticationService.SignIn(customer, true);
}
return ApiReturn.Success;
}
else
return ApiReturn.Failed; }
#endregion //其他的实现略 }

可以看出我们的自定义UcApiService继承了 一开始提到的sdk中的UcApiBase,而UcApiBase实现了IHttpHandler和IRequiresSessionState接口,所以在我们的方法中可以直接调用

UcApiService的PR方法。UcApiBase鸡肋中还有好多的方法等待实现,我就不一一列出了,具体可以自己去查看。我们就看这个同步登陆的方法,大体意思就是ucenter下属有其它站点登陆了,我们只要在这个方法中查找的这个用户,并且设置他在本站的状态也为登陆状态,说白了就是授权用户登录本站,只是不需要用户再次的输入账号密码而已。

第四步,上一步是ucenter通知我们有用户从其他站登录了,要求我们这里也登录,那么如果有会员通过我们这个站登录了,我们也是要告诉ucenter的,所以我们这里需要在会员登录成功的情况下,告诉ucenter,这个会员已经成功登录了,你可以让他在其他站也进行登录,具体的实现就是在生成用户凭证的时候调用sdk中IUcClient中的UserLogin方法,如果登录成功,改方法会返回一段js脚本,我们只需要把这段js脚本放到页面上即可。具体代码如下

    /// <summary>
/// ucenter自定义 登陆认证和 退出认证 实现
/// </summary>
public class NopUiUcenterAuthenticationService : INopUiUcenterAuthenticationService
{
#region Fields
/// <summary>
/// HttpContextBase
/// </summary>
private HttpContextBase _httpContext;
//private readonly ICustomerService _customerService;
/// <summary>
/// CustomerSettings
/// </summary>
private readonly CustomerSettings _customerSettings;
/// <summary>
/// UCenterSetting
/// </summary>
private UCenterSetting _uCenterSetting;
/// <summary>
/// IUcClient
/// </summary>
private IUcClient _uclient;
/// <summary>
/// 日志服务
/// </summary>
private ILogger _logger;
// private ICustomerActivityService _customerActivityService;
#endregion #region Ctor
/// <summary>
/// ctor
/// </summary>
/// <param name="httpContext">HttpContextBase</param>
/// <param name="customerSettings">CustomerSettings</param>
/// <param name="_uCenterSetting">UCenterSetting</param>
/// <param name="_uclient">IUcClient</param>
/// <param name="_logger">日志服务</param>
public NopUiUcenterAuthenticationService(HttpContextBase httpContext,
// ICustomerService customerService,
CustomerSettings customerSettings,
UCenterSetting _uCenterSetting,
IUcClient _uclient, ILogger _logger
// ICustomerActivityService _customerActivityService
)
{
this._httpContext = httpContext;
// this._customerService = customerService;
this._customerSettings = customerSettings;
this._uCenterSetting = _uCenterSetting;
this._uclient = _uclient;
this._logger = _logger;
//this._customerActivityService = _customerActivityService;
}
#endregion #region Methods
/// <summary>
/// 认证
/// </summary>
/// <param name="customer">Customer</param>
public void SignIn(Customer customer)
{
if (!_uCenterSetting.AvailableUcenter || _httpContext.Request.Form["Password"] == null)
return;
//同步登陆
try
{
string Password = _httpContext.Request.Form["Password"].ToString().Trim();
//IUcClient client = new UcClient();
UcUserLogin user = null;
if (_customerSettings.UsernamesEnabled)
user = _uclient.UserLogin(customer.Username, Password);//登陆
else
user = _uclient.UserLogin(customer.Email, Password, LoginMethod.Mail);//登陆
if (user != null && user.Success)//判断是否登陆成功
{
switch (user.Result)
{
case LoginResult.Success:
//保存到会话中
// _customerActivityService.InsertActivity("uCenter", "客户从本地登陆,并且成功同步到uCenter中", customer);
_httpContext.Session[Constants.UcenterLoginSessionKey] = _uclient.UserSynlogin(user.Uid);
break;
case LoginResult.NotExist:
//用户不存在 那么就注册到ucenter吧
//_logger
var registerResult = _uclient.UserRegister(customer.Username, Password, customer.Email);
if (registerResult.Result == RegisterResult.Success)
{
// _customerActivityService.InsertActivity("uCenter", "客户在本地存在,但是在ucenter中不存在,此处注册此用户到uCenter中成功", customer);
_httpContext.Session[Constants.UcenterLoginSessionKey] = _uclient.UserSynlogin(registerResult.Uid);
}
else
_logger.Error(registerResult.Result.ToString() + "---同步登陆到uCenter时异常,描述:本地已经存在的用户但是ucenter中没有,试图向ucenter中注册此用户的时候,注册失败", null, customer);
break;
case LoginResult.PassWordError:
//密码不对,那就把用户中心的密码改成和本商城中一样的呗
var s = _uclient.UserEdit(customer.Username, null, Password, null, true);
if (s.Result == UserEditResult.Success)
{
//_customerActivityService.InsertActivity("uCenter", "客户在本地和ucenter中的密码不一样,但是以本商城的密码为主,所以到ucenter中修改此用户的登陆密码,成功", customer);
_httpContext.Session[Constants.UcenterLoginSessionKey] = _uclient.UserSynlogin(user.Uid);
}
break;
case LoginResult.QuestionError:
break;
default:
break;
}
}
else
{
_logger.Error("ucteter同步异常,请查看ucenter配置页的配置是否正确", null, customer);
}
}
catch (Exception ex)
{ _logger.Error("ucteter同步异常", ex, customer);
}
} /// <summary>
/// 取消认证
/// </summary>
public void SignOut()
{
if (_uCenterSetting.AvailableUcenter)
_httpContext.Session[Constants.UcenterLoginOutSessionKey] = _uclient.UserSynLogout();
}
#endregion
}

我们把返回的js脚本方法 会话中,再跳转的时候把这段脚本打到页面上,再删除这段会话即可。

第五步,这步是写配置信息,因为原始类库的配置信息都写到它自己的App.config中去了,但是我这里把作者从配置文件读出配置的方式改成从数据库读取了,配置信息如下图所示

第六步,检查本地服务器和UCenter服务器是否能正常通信

第七步,去UCenter添加此应用,具体怎么填的图片如下:

填写完以后到列表页面看到如下所示,则表示通信成功

 现在我们就可以测试是否可以正常同步了。

打开discuz登录一个用户后,再到我们商城中会发现,改用户已经登录了商城,就算该用户在我们商城不存在,我们也会在同步的时候自动注册该用户。

 

到此 基本上从三美到 discuz 的同步基本完成。

但是,我不知道discuz是故意的还是无意的,这其中一共有三个问题

  1. 我从discuz登录用户,却无法同步 到三美商城。
  2. 从三美商城注册的用户,无法即时同步到discuz,需要在discuz登录一下,以后就可以同步了,及需要激活!
  3. 从discuz注册的用户,无法即时同步 到三美商城。

要想解决这三个问题,都得要从discuz入手,首先解决第一个问题:

  打开discuz安装路径下 \bbs\uc_client\data\cache\apps.php:

你会发现只有discuz x 本身应用,所以就不会同步登陆,我也不知道什么原因造成。

我们把三美的应用也加进去即可解决从discuz登录不同步到三美商城的问题

接着解决第二个问题:

第二个问题产生的主要原因是,我们注册的用户,同步登陆的时候,discuz并没有把这个用户添加到他的用户表里面,而是用户激活后才添加到他自己的用户表,找到原因后就很好解决了,

我们只需要在用户同步登陆的时候把用户添加到用户表中即可,

修改文件:/api/uc.php

    function synlogin($get, $post) {
global $_G; if(!API_SYNLOGIN) {
return API_RETURN_FORBIDDEN;
} header('P3P: CP="CURa ADMa DEVa PSAo PSDo OUR BUS UNI PUR INT DEM STA PRE COM NAV OTC NOI DSP COR"'); $cookietime = 31536000;
$uid = intval($get['uid']);
if(($member = getuserbyuid($uid, 1))) {
dsetcookie('auth', authcode("$member[password]\t$member[uid]", 'ENCODE'), $cookietime);
}else{
$query = DB::query("SELECT email FROM ".DB::table('ucenter_members')." WHERE uid='$uid'");
if($a = DB::fetch($query)){
$email = $a['email'];
}else{
$email = $get['email'];
}
$username = $get['username'];
$password = md5(time().rand(100000, 999999));
//$email = $get['email'];
$ip = $_SERVER['REMOTE_ADDR'];
$time = time();
$userdata = array(
'uid' => $uid,
'username' => $username,
'password' => $password,
'email' => $email,
'adminid' => 0,
'groupid' => 10,
'regdate' => $time,
'credits' => 0,
'timeoffset' => 9999
);
DB::insert('common_member', $userdata);
$status_data = array(
'uid' => $uid,
'regip' => $ip,
'lastip' => $ip,
'lastvisit' => $time,
'lastactivity' => $time,
'lastpost' => 0,
'lastsendmail' => 0,
);
DB::insert('common_member_status', $status_data);
DB::insert('common_member_profile', array('uid' => $uid));
DB::insert('common_member_field_forum', array('uid' => $uid));
DB::insert('common_member_field_home', array('uid' => $uid));
DB::insert('common_member_count', array('uid' => $uid));
if(($member = getuserbyuid($uid, 1))) {
dsetcookie('auth', authcode("$member[password]\t$member[uid]", 'ENCODE'), $cookietime);
}
}
}

保存上述代码即可解决第二个问题

下面解决最后一个问题,这个问题其实本质和第二个很相似,只需要在用户注册的时候调用一下登陆方法即可。

具体参考方法见:http://www.discuz.net/thread-2356743-1-1.html
 
 
至此 就可以实现商城和discuz的用户同步了,本篇文章是基于 nopcommerce3.5和discuz x3.2的同步解决方案。

.net mvc通过ucenter和 discuz的整合,nopcommerce ucenter 插件的方式实现的更多相关文章

  1. 织梦系统与discuz论坛整合方法

    如何完成dedecms模板系统与discuz论坛整合呢? 这里的整合指会员信息,会员登陆.退出的同步:论坛信息的引用:等等. 首先,我们先来安装织梦(dedecms)系统. 然后,我们在网站根目录下建 ...

  2. Discuz!nt整合心得

    最近研究了下Discuz!nt的整合,因为是网上找的实例,有个地方的写错了,导致纠结了一整天,这里分享出来. Discuz!nt提供了整合工具DiscuzToolkit,用于调用Discuz!nt A ...

  3. UCenter 与 DIscuz 通信失败的解决方法

    问题状况:Discuz 用户无法成功修改头像且帖子中上传的图片无法保存.进入 Discuz 后台检查,一切正常:进入 UCenter 检查后发现在"应用管理"中与 Discuz 论 ...

  4. DWZ(JUI) 教程 中如何整合第三方jQuery插件

    Query插件一般是$(document).ready()中初始化 $(document).ready(function(){  // 文档就绪,初始化jQuery插件| });  // 或者或缩写形 ...

  5. SpringBoot整合Servlet的两种方式

    SpringBoot整合Servlet有两种方式: 1.通过注解扫描完成Servlet组件的注册: 2.通过方法完成Servlet组件的注册: 现在简单记录一下两种方式的实现 1.通过注解扫描完成Se ...

  6. spring boot 整合pagehelper分页插件

    Spring Boot 整合pagehelper分页插件 测试环境: spring boot  版本 2.0.0.M7 mybatis starter 版本  1.3.1 jdk 1.8 ------ ...

  7. SpringBoot从入门到精通二(SpringBoot整合myBatis的两种方式)

    前言 通过上一章的学习,我们已经对SpringBoot有简单的入门,接下来我们深入学习一下SpringBoot,我们知道任何一个网站的数据大多数都是动态的,也就是说数据是从数据库提取出来的,而非静态数 ...

  8. SpringBoot系列-整合Mybatis(XML配置方式)

    目录 一.什么是 MyBatis? 二.整合方式 三.实战 四.测试 本文介绍下SpringBoot整合Mybatis(XML配置方式)的过程. 一.什么是 MyBatis? MyBatis 是一款优 ...

  9. Spring Boot 整合 Shiro ,两种方式全总结!

    在 Spring Boot 中做权限管理,一般来说,主流的方案是 Spring Security ,但是,仅仅从技术角度来说,也可以使用 Shiro. 今天松哥就来和大家聊聊 Spring Boot ...

随机推荐

  1. javascript代码复用模式(三)

    前面谈到了javascript的类式继承.这篇继续部分类式继承,及一些现代继承. 类式继承模式-代理构造函数 这种模式通过断开父对象与子对象之间原型之间的直接链接关系,来解决上次说到的共享一个原型所带 ...

  2. MacOSX和Windows 8的完美融合

    MacOSX和Windows8的完美融合 一般情况下我们要在MACOS系统下运行Windows软件怎么办呢?一种方法我们可以装CrossOver这款软件,然后在configuration->in ...

  3. 【MySQL】触发器学习

    MySQL手册中对触发器的定义是: 触发程序是与表有关的命名数据库对象,当表上出现特定事件时,将激活该对象.表必须是永久性表,不能将触发程序与临时表与视图关联起来. 相同触发程序动作时间和事件的给定表 ...

  4. 【缓存】利用Cache防止同一帐号重复登录

    需求概要 对于B/S应用系统中客户经常会提出同一帐号不能重复登录的需求,就是说,用某一帐号登录系统后,在系统不超时的情况下,任何人都不能再用目前已登录的帐号登录系统.包括我目前的项目中同样有这一需求. ...

  5. .NET 命名规范 代码示例

    class Person { /// <summary> /// 公有字段.属性 首字母大写 /// </summary> public string FirstName; p ...

  6. c++ builder ListView实现可编辑任意列(转)

    // --------------------------------------------------------------------------- // Form的构造函数中填充StrinG ...

  7. JSON对象遍历方法

    JSON对象提前不知道其属性和结构,遍历其值 var json2 = { "name": "txt1", "name2": "tx ...

  8. Visual Studio 中 Tab 转换为空格的设置

    Visual Studio 中 Tab 转换为空格的设置 在 Visual Studio 中写代码时,按 Tab 键,会自动进行缩进.有时希望实现按 Tab 键,出现多个空格的效果.Visual St ...

  9. C puzzles详解【13-15题】

    第十三题 int CountBits(unsigned int x) { ; while(x) { count++; x = x&(x-); } return count; } 知识点讲解 位 ...

  10. Linux下vi编辑器粘贴复制剪切功能

    RedHat 9.0 Linux下vi编辑器实现简单的粘贴复制剪切功能": 如果想把文件内的第三行内容黏贴到第十五行: 1.进入你的文件,(处于命令模式,而不是编辑模式) 2.将你的光标移到 ...