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. Sql语句直接返回XML文件

    通过Sql语句直接返回XML文件 select UserID,UserName,AccountName,LoginPassword from users for xml raw('Users') ,r ...

  2. 一个不简单的Procedure body例子

    create or replace package body CountBankData_20150617 is type cursorCommon is ref cursor; --游标类型 str ...

  3. Sass基础语法

    Sass是CSS3语言的扩展,在CSS的基础之上添加了新特性和语法,能省事地写出更好的样式表.Sass引擎是基于Ruby的. 导入Sass文件: @import "colors" ...

  4. APUE第4章 文件和目录

    4.2 文件函数 #include <sys/stat.h> int stat(const char *restrict pathname, struct stat *restrict b ...

  5. Windows phone 8 学习笔记(6) 多任务(转)

    Windows phone 8 是一个单任务操作系统,任何时候都只有一个应用处于活跃状态,这里的多任务是指对后台任务的支持.本节我们先讲讲应用程序的运行状态,然后看看支持的后台任务,包括:后台代理.后 ...

  6. js动态改变图片热区坐标,手机端图片热区自适应

    <img id='banner1' src="images/banner.jpg" usemap="#banner" border="0&quo ...

  7. 设计模式-代理模式(Proxy)

    应用场景: 领导都有秘书,一般会代理领导的部分职能角色,处理签字.报销.开会等任务.很多新人可能都只知道秘书的存在,毕竟每天与其打交道,不知道领导的存在.但是领导的的确确是真实存在的. 场景说明: 代 ...

  8. 简单记事本程序java源码项目

    代码如下 import java.awt.*; import java.io.*; import java.awt.datatransfer.*; import java.awt.event.*; p ...

  9. Splash Screen开场屏在Android中的实现

    很多网友可能发现近期Tencent推出的手机QQ Android版包含了一个开场屏Splash Screen载入效果,通常游戏或大型软件打开时可能需要一个释放解析资源的过程,需要一个前台的动画播放和后 ...

  10. C puzzles详解【46-50题】

    第四十六题 What does the following macro do? #define ROUNDUP(x,n) ((x+n-1)&(~(n-1))) 题目讲解: 参考:http:// ...