.net mvc通过ucenter和 discuz的整合,nopcommerce ucenter 插件的方式实现
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是故意的还是无意的,这其中一共有三个问题
- 我从discuz登录用户,却无法同步 到三美商城。
- 从三美商城注册的用户,无法即时同步到discuz,需要在discuz登录一下,以后就可以同步了,及需要激活!
- 从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);
}
}
}
保存上述代码即可解决第二个问题
下面解决最后一个问题,这个问题其实本质和第二个很相似,只需要在用户注册的时候调用一下登陆方法即可。
.net mvc通过ucenter和 discuz的整合,nopcommerce ucenter 插件的方式实现的更多相关文章
- 织梦系统与discuz论坛整合方法
如何完成dedecms模板系统与discuz论坛整合呢? 这里的整合指会员信息,会员登陆.退出的同步:论坛信息的引用:等等. 首先,我们先来安装织梦(dedecms)系统. 然后,我们在网站根目录下建 ...
- Discuz!nt整合心得
最近研究了下Discuz!nt的整合,因为是网上找的实例,有个地方的写错了,导致纠结了一整天,这里分享出来. Discuz!nt提供了整合工具DiscuzToolkit,用于调用Discuz!nt A ...
- UCenter 与 DIscuz 通信失败的解决方法
问题状况:Discuz 用户无法成功修改头像且帖子中上传的图片无法保存.进入 Discuz 后台检查,一切正常:进入 UCenter 检查后发现在"应用管理"中与 Discuz 论 ...
- DWZ(JUI) 教程 中如何整合第三方jQuery插件
Query插件一般是$(document).ready()中初始化 $(document).ready(function(){ // 文档就绪,初始化jQuery插件| }); // 或者或缩写形 ...
- SpringBoot整合Servlet的两种方式
SpringBoot整合Servlet有两种方式: 1.通过注解扫描完成Servlet组件的注册: 2.通过方法完成Servlet组件的注册: 现在简单记录一下两种方式的实现 1.通过注解扫描完成Se ...
- spring boot 整合pagehelper分页插件
Spring Boot 整合pagehelper分页插件 测试环境: spring boot 版本 2.0.0.M7 mybatis starter 版本 1.3.1 jdk 1.8 ------ ...
- SpringBoot从入门到精通二(SpringBoot整合myBatis的两种方式)
前言 通过上一章的学习,我们已经对SpringBoot有简单的入门,接下来我们深入学习一下SpringBoot,我们知道任何一个网站的数据大多数都是动态的,也就是说数据是从数据库提取出来的,而非静态数 ...
- SpringBoot系列-整合Mybatis(XML配置方式)
目录 一.什么是 MyBatis? 二.整合方式 三.实战 四.测试 本文介绍下SpringBoot整合Mybatis(XML配置方式)的过程. 一.什么是 MyBatis? MyBatis 是一款优 ...
- Spring Boot 整合 Shiro ,两种方式全总结!
在 Spring Boot 中做权限管理,一般来说,主流的方案是 Spring Security ,但是,仅仅从技术角度来说,也可以使用 Shiro. 今天松哥就来和大家聊聊 Spring Boot ...
随机推荐
- javascript代码复用模式(三)
前面谈到了javascript的类式继承.这篇继续部分类式继承,及一些现代继承. 类式继承模式-代理构造函数 这种模式通过断开父对象与子对象之间原型之间的直接链接关系,来解决上次说到的共享一个原型所带 ...
- MacOSX和Windows 8的完美融合
MacOSX和Windows8的完美融合 一般情况下我们要在MACOS系统下运行Windows软件怎么办呢?一种方法我们可以装CrossOver这款软件,然后在configuration->in ...
- 【MySQL】触发器学习
MySQL手册中对触发器的定义是: 触发程序是与表有关的命名数据库对象,当表上出现特定事件时,将激活该对象.表必须是永久性表,不能将触发程序与临时表与视图关联起来. 相同触发程序动作时间和事件的给定表 ...
- 【缓存】利用Cache防止同一帐号重复登录
需求概要 对于B/S应用系统中客户经常会提出同一帐号不能重复登录的需求,就是说,用某一帐号登录系统后,在系统不超时的情况下,任何人都不能再用目前已登录的帐号登录系统.包括我目前的项目中同样有这一需求. ...
- .NET 命名规范 代码示例
class Person { /// <summary> /// 公有字段.属性 首字母大写 /// </summary> public string FirstName; p ...
- c++ builder ListView实现可编辑任意列(转)
// --------------------------------------------------------------------------- // Form的构造函数中填充StrinG ...
- JSON对象遍历方法
JSON对象提前不知道其属性和结构,遍历其值 var json2 = { "name": "txt1", "name2": "tx ...
- Visual Studio 中 Tab 转换为空格的设置
Visual Studio 中 Tab 转换为空格的设置 在 Visual Studio 中写代码时,按 Tab 键,会自动进行缩进.有时希望实现按 Tab 键,出现多个空格的效果.Visual St ...
- C puzzles详解【13-15题】
第十三题 int CountBits(unsigned int x) { ; while(x) { count++; x = x&(x-); } return count; } 知识点讲解 位 ...
- Linux下vi编辑器粘贴复制剪切功能
RedHat 9.0 Linux下vi编辑器实现简单的粘贴复制剪切功能": 如果想把文件内的第三行内容黏贴到第十五行: 1.进入你的文件,(处于命令模式,而不是编辑模式) 2.将你的光标移到 ...