zoukankan      html  css  js  c++  java
  • .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(100000).ToString(),
                            VendorId = 0,
                            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 > 0)
                            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安装路径下 bsuc_clientdatacacheapps.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]	$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]	$member[uid]", 'ENCODE'), $cookietime);
                }
            }
        }
    View Code

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

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

    具体参考方法见:http://www.discuz.net/thread-2356743-1-1.html
     
     
    至此 就可以实现商城和discuz的用户同步了,本篇文章是基于 nopcommerce3.5和discuz x3.2的同步解决方案。
  • 相关阅读:
    jdk动态代理底层实现
    spring-FactoryBean
    大型网站技术架构 核心原理与案例分析 pdf
    实战JAVA虚拟机 JVM故障诊断与性能优化 pdf
    《实战Java高并发程序设计》pdf
    mysql-注意点
    Json入门
    inflate, findViewById与setContentView的区别与联系
    提高编程能力的7条建议
    JDBC之一:JDBC快速入门
  • 原文地址:https://www.cnblogs.com/drzhong/p/4347173.html
Copyright © 2011-2022 走看看