`
bukebuhao
  • 浏览: 88730 次
  • 性别: Icon_minigender_1
  • 来自: 绍兴
社区版块
存档分类
最新评论

java同步discuz账号

阅读更多

 

网站整合discuz账号,实现登录最起码有两个方向。1.相互不干涉,登录的时候,各自登录成功;2.就是大家共用一个登录标记,例如共用cookie实现。

至于第一种有很多实现方式。例如登录主网站W(web)的时候,隐藏登录D(discuz)论坛;还有就是异步登录,利用js登录。例如
http://code.google.com/p/discuz-ucenter-api-for-java/(java版UC API官网)就是利用uc的api生成一段登录的js脚本,调用登录脚本实现异步登录实现,这里的亮点就是利用api实现,因为现在流行组装性的,互不干涉的实现方式。如果想实现的比较漂亮,可采用这种方式。只是uc的实现略微麻烦,总的就是先实现通信,就是设置密钥;其次,才能调用api,但是这个api是针对uc的,不是直接针对D的,uc的api负责和D再同步,W--->U---->D,每次都是这样来回通信,可实现登陆,注册,修改信息等多个功能。具体的可参考官网。

针对我们的公司网站情况,还是不要采用这种过于麻烦的做法。我们只是想简单的实现同步登陆,同步注册而已,另外我们也可直接访问数据库,又不是第三方用户的,没必要搞api,因此,想着实现cookie共享就可了。为啥实现cookie共享的,这就由D的账号登录机制决定的。
D的账号登录机制,基本原理就是验证cookie的auth,利用加密算法把{password}/t{uid}加密进去,每次请求处理的时候,根据对应的解密算法解析auth,判断uid是否存在,就可判断是否登录。通过分析可知,所有的关键就是要掌握算法,只有搞定算法一切就ok。

接下来就要着重分析算法的实现啦。参考java版UC API官网可知,基本的算法,uc_authcode方法是java版实现/source/function/function_core.php里的authcode方法,MD5也类似一一对应的,只是java版里多了一步urlencode的GBK的编码转换而已。到这里似乎好像一切都很明朗,很简单化了。不过实际调用的时候又发现,所有的关键问题是key,key的生成,查看/discuz/upload/source/class/discuz/discuz_application.php的_init_input方法可知,authkey=md5(配置文件authkey和cookie的saltkey合并),为何是在这个方法,注意$discuz->init()这个方法,所有的基础操作都是由discuz_application类实现的,类似于java里的servlet,基础控制类。因此需要配置获取D论坛的config/config_global.php里的$_config[ 'security' ][' authkey' ]值,还有随机生成8个字母的盐值。到这里算法的key已生成。

     public static void setBbsUserCookie(HttpServletResponse response,
               BbsUser user) {
          String saltkey = WebImpUtils.getRandomString(8);
          String cookieInfo = MessageFormat.format("{0}\t{1}",
                    user.getPassword(), String.valueOf(user.getUid()));
          String auth = BBsUtils.urlencode(BBsUtils.uc_authcode(cookieInfo,
                    "ENCODE", BBsUtils.md5(BBS_AUTH_KEY + saltkey)));
          WebImpUtils.setUserCookie(response, COOKIE_PRE + "auth", auth,
                    COOKIE_DOMAIN);
          WebImpUtils.setUserCookie(response, COOKIE_PRE + "saltkey", saltkey,
                    COOKIE_DOMAIN);
     }
 

其次,就是cookie的问题啦,cookie有限制,二级域名可直接在一级域名写cookie,当然也可读,但是反过来,一级域名就不可在二级域名下写cookie,也就是要实现cookie共享,只有在一级域名下,配置一下论坛的$_config[ 'cookie'][ 'cookiedomain' ] = '.xxx.com' ;,还有cookie的名字是否有前缀,$_config[ 'cookie'][ 'cookiepre' ]。具体请参考/config/config_global.php。


附件是java版实现cookie共享登录实现。直接调用setBbsUserCookie方法就可了,至于注册用户,直接截获论坛的注册的时候插入数据库的sql,插入数据生成的。


package com.ccc.cn.work.app;

import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.MessageFormat;

import javax.servlet.http.HttpServletResponse;

import com.ccc.cn.work.core.utils.WebImpUtils;
import com.ccc.cn.work.service.bbs.Base64;
import com.ccc.cn.work.service.bbs.BbsUser;

/**
* 
************************************************ 
* @file: BBsUtils.java
* @Copyright: 2012 Yiwu China Commodity City Information Technology Co., Ltd.
*             All right reserved.
************************************************ 
* @package: com.ccc.cn.work.service.bbs
* @class: BBsUtils
* @description:
* 
* @author: bukebuhao
* @since: 2012-7-27-上午09:25:27
* @history:
* 
*/
public class BBsUtils {
     /**
     * config/config_global.php
     */
     private static String BBS_AUTH_KEY = ""; //$_config[ 'security' ][' authkey' ]

     private static String COOKIE_PRE = ""; //$_config[ 'cookie'][ 'cookiepre' ]
     private static String COOKIE_DOMAIN = ".xxx.com";//一级域名
     private static String COOKIE_PATH = "/";
     static {
          COOKIE_PRE = COOKIE_PRE
                    + BBsUtils.md5(COOKIE_PATH + "|" + COOKIE_DOMAIN).substring(0,
                              4) + "_";
     }

     public static String urlencode(String value) {
          try {
               return URLEncoder.encode(value, "GBK");
          } catch (UnsupportedEncodingException e) {
               return e.getMessage();
          }
     }

     public static String md5(String input) {
          MessageDigest md;
          try {
               md = MessageDigest.getInstance("MD5");
          } catch (NoSuchAlgorithmException e) {
               e.printStackTrace();
               return null;
          }
          return byte2hex(md.digest(input.getBytes()));
     }

     public static String md5(long input) {
          return md5(String.valueOf(input));
     }

     public static String base64_decode(String input) {
          try {
               return new String(Base64.decode(input.toCharArray()), "iso-8859-1");
          } catch (Exception e) {
               return e.getMessage();
          }
     }

     public static String base64_encode(String input) {
          try {
               return new String(Base64.encode(input.getBytes("iso-8859-1")));
          } catch (Exception e) {
               return e.getMessage();
          }
     }

     public static String byte2hex(byte[] b) {
          StringBuffer hs = new StringBuffer();
          String stmp = "";
          for (int n = 0; n < b.length; n++) {
               stmp = (java.lang.Integer.toHexString(b[n] & 0XFF));
               if (stmp.length() == 1)
                    hs.append("0").append(stmp);
               else
                    hs.append(stmp);
          }
          return hs.toString();
     }

     public static String substr(String input, int begin, int length) {
          return input.substring(begin, begin + length);
     }

     public static String substr(String input, int begin) {
          if (begin > 0) {
               return input.substring(begin);
          } else {
               return input.substring(input.length() + begin);
          }
     }

     public static long microtime() {
          return System.currentTimeMillis();
     }

     public static long time() {
          return System.currentTimeMillis() / 1000;
     }

     public static String sprintf(String format, long input) {
          String temp = "0000000000" + input;
          return temp.substring(temp.length() - 10);
     }

     /**
     * 字符串加密以及解密函数
     * 
     * @param string
     *            string 原文或者密文
     * @param string
     *            operation 操作(ENCODE | DECODE), 默认为 DECODE
     * @param string
     *            key 密钥
     * @param int expiry 密文有效期, 加密时候有效, 单位 秒,0 为永久有效
     * @return string 处理后的 原文或者 经过 base64_encode 处理后的密文
     * 
     * @example
     * 
     *          a = authcode('abc', 'ENCODE', 'key'); b = authcode(a, 'DECODE',
     *          'key'); // b(abc)
     * 
     *          a = authcode('abc', 'ENCODE', 'key', 3600); b = authcode('abc',
     *          'DECODE', 'key'); // 在一个小时内,b(abc),否则 b 为空
     */
     public static String uc_authcode(String string, String operation) {
          return uc_authcode(string, operation, null);
     }

     public static String uc_authcode(String string, String operation, String key) {
          return uc_authcode(string, operation, key, 0);
     }

     public static String uc_authcode(String string, String operation,
               String key, int expiry) {

          int ckey_length = 4; // note 随机密钥长度 取值 0-32;
          // note 加入随机密钥,可以令密文无任何规律,即便是原文和密钥完全相同,加密结果也会每次不同,增大破解难度。
          // note 取值越大,密文变动规律越大,密文变化 = 16 的 ckey_length 次方
          // note 当此值为 0 时,则不产生随机密钥

          // key = md5( key!=null ? key : UC_KEY);
          key = md5(key);
          String keya = md5(substr(key, 0, 16));
          String keyb = md5(substr(key, 16, 16));
          String keyc = ckey_length > 0 ? (operation.equals("DECODE") ? substr(
                    string, 0, ckey_length)
                    : substr(md5(microtime()), -ckey_length)) : "";

          String cryptkey = keya + md5(keya + keyc);
          int key_length = cryptkey.length();

          string = operation.equals("DECODE") ? base64_decode(substr(string,
                    ckey_length)) : sprintf("%010d", expiry > 0 ? expiry + time()
                    : 0)
                    + substr(md5(string + keyb), 0, 16) + string;
          int string_length = string.length();

          StringBuffer result1 = new StringBuffer();

          int[] box = new int[256];
          for (int i = 0; i < 256; i++) {
               box[i] = i;
          }

          int[] rndkey = new int[256];
          for (int i = 0; i <= 255; i++) {
               rndkey[i] = (int) cryptkey.charAt(i % key_length);
          }

          int j = 0;
          for (int i = 0; i < 256; i++) {
               j = (j + box[i] + rndkey[i]) % 256;
               int tmp = box[i];
               box[i] = box[j];
               box[j] = tmp;
          }

          j = 0;
          int a = 0;
          for (int i = 0; i < string_length; i++) {
               a = (a + 1) % 256;
               j = (j + box[a]) % 256;
               int tmp = box[a];
               box[a] = box[j];
               box[j] = tmp;

               result1
                         .append((char) (((int) string.charAt(i)) ^ (box[(box[a] + box[j]) % 256])));

          }

          if (operation.equals("DECODE")) {
               String result = result1.substring(0, result1.length());
               if ((Integer.parseInt(substr(result.toString(), 0, 10)) == 0 || Long
                         .parseLong(substr(result.toString(), 0, 10))
                         - time() > 0)
                         && substr(result.toString(), 10, 16).equals(
                                   substr(md5(substr(result.toString(), 26) + keyb),
                                             0, 16))) {
                    return substr(result.toString(), 26);
               } else {
                    return "";
               }
          } else {
               return keyc + base64_encode(result1.toString()).replaceAll("=", "");
          }
     }

     /**
     * 
     * @description setBbsUserCookie(这里用一句话描述这个方法的作用)
     * @conditions (这里描述这个方法适用条件 – 可选)
     * @param response
     * @param user
     *            void
     * @exception
     * @since 1.0.0
     */
     public static void setBbsUserCookie(HttpServletResponse response,
               BbsUser user) {
          String saltkey = WebImpUtils.getRandomString(8);
          String cookieInfo = MessageFormat.format("{0}\t{1}",
                    user.getPassword(), String.valueOf(user.getUid()));
          String auth = BBsUtils.urlencode(BBsUtils.uc_authcode(cookieInfo,
                    "ENCODE", BBsUtils.md5(BBS_AUTH_KEY + saltkey)));
          WebImpUtils.setUserCookie(response, COOKIE_PRE + "auth", auth,
                    COOKIE_DOMAIN);
          WebImpUtils.setUserCookie(response, COOKIE_PRE + "saltkey", saltkey,
                    COOKIE_DOMAIN);
     }

     /**
     * 
     * @description clearBbsUserCookie(这里用一句话描述这个方法的作用)
     * @conditions (这里描述这个方法适用条件 – 可选)
     * @param response
     *            void
     * @exception
     * @since 1.0.0
     */
     public static void clearBbsUserCookie(HttpServletResponse response) {
          WebImpUtils.removeCookie(response, COOKIE_PRE + "auth", COOKIE_DOMAIN);
          WebImpUtils.removeCookie(response, COOKIE_PRE + "saltkey",
                    COOKIE_DOMAIN);
     }
}
  至于其中用到的WebImpUtils自己参考实现就可了,很简单的,例如继承org.springframework.web.util.WebUtils.
分享到:
评论
1 楼 wqp310520 2013-09-05  
给个demo啊

相关推荐

    java整合discuz论坛同步注册同步登录资源打包

    java整合discuz论坛同步注册同步登录资源打包,供大家参考参考。

    java discuz 同步

    Java 与 Discuz 用户同步是将用户账户信息在Java应用程序和Discuz论坛之间进行一致性的更新,以便用户在任一平台上的登录状态和信息能够实时反映到另一个平台。这一过程通常涉及设置通信路径、配置安全密钥以及实现...

    discuz-ucenter-api-for-java

    (社区论坛系统)、SupeSite(门户CMS系统)、X-Space(博客系统)从用户资源层面进行无缝整合,使得账号实现统一管理,在任何一个系统中进行注册、登录、注销等操作时,该账号在其他系统中的会话状态也将同步更新,...

    最完美的Discuz UCenter的JAVA API接口【java包】

    因此,"最完美的Discuz UCenter的JAVA API接口【java包】"的出现解决了这一困境,使得 Java 应用程序也能无缝地与 Discuz! UCenter 进行交互。 这个 Java 开发包(dzclient4j)提供了必要的工具和类库,让 Java ...

    Discuz 自动同步登陆通达OA的完美解决办法

    Discuz 自动同步登陆通达OA的完美解决办法,自己看了一下UCenter、Discuz同步登陆的机制,提炼出了以下用于同步登陆Discuz的代码

    discuz与java通过cookie共享登陆

    **会话管理**:为了安全,Java应用可能会有自己的会话管理系统,这时需要将从Discuz接收到的Cookie信息转化为Java应用的会话ID,或者维护一个映射关系,确保用户在Java应用中的行为也能根据Discuz的登录状态同步。...

    ucenter discuz Java api

    首先,Ucenter Discuz Java API 是一套基于Java语言的接口,允许开发者在Java环境中与Ucenter进行通信,实现用户注册、登录、信息同步等功能。它为开发者提供了便捷的方式来接入Ucenter服务,简化了与社区系统的集成...

    discuz加密解密函数 java版

    标题 "Discuz加密解密函数 Java版" 涉及的是使用Java实现的与Discuz论坛系统相关的加密和解密功能。Discuz是一款流行的开源社区论坛软件,其内部使用了一系列的加密算法来保护用户数据的安全,例如用户密码、论坛...

    最完美的Discuz UCenter的JAVA API接口(含源码)

    通过这些接口,开发者可以轻松地在Java应用中创建用户账号、管理用户权限,以及同步用户的论坛活动。 项目的描述中提到,长期以来Java开发者面临的一个问题就是缺乏与PHP社区系统(如Discuz!)的集成工具。由于许多...

    ucenter discuz Java api接口

    ucenter discuz Java api接口ucenter discuz Java api接口ucenter discuz Java api接口ucenter discuz Java api接口ucenter discuz Java api接口

    源码!整合discuz与网站的同步登录

    整合discuz与网站的同步登录】 在互联网应用开发中,用户登录体验的统一性和便捷性是提升用户体验的重要一环。Discuz! 是一款广泛应用的社区论坛软件,而许多网站则采用自定义的会员系统。当用户在主站登录后,能够...

    Discuz与ThinkPHP同步登录

    《Discuz与ThinkPHP同步登录实现详解》 在互联网应用开发中,用户登录系统的统一管理是常见的需求。本文将深入探讨如何实现Discuz论坛系统与基于ThinkPHP框架的应用之间的同步登录,帮助开发者理解和掌握这一技术。...

    discuz7.x同步登录退出修改密码

    Discuz! 是一款知名的论坛软件,它提供了丰富的社区功能和高度的可定制性。在 Discuz! 7.x 版本中,用户管理和权限控制是其核心组成部分。本测试例子主要涉及的是用户登录、退出以及密码修改的同步操作,这对于确保...

    ucdemo discuz ucenter api for java

    社区平台设计的Java实现的Ucenter API接口,它旨在帮助开发者在Java环境中与Discuz! Ucenter进行无缝对接,实现单点登录(Single Sign-On, SSO)功能。Ucenter是Discuz!提供的一种用户中心服务,它能够统一管理多个...

    ucenter,uchome,discuz同步注册免激活同步登录

    Ucenter的主要功能是提供统一的身份认证服务,它可以连接并管理多个基于Comsenz产品的站点,确保用户只需注册一次,就能在所有关联的应用中使用同一账号。这样既简化了用户的登录流程,也便于网站管理员管理用户数据...

    java_to_discuz单点登录手册.xls

    java_to_discuz单点登录手册

    java(jsp)整合discuz同步登录功能详解

    老师说可以搭建开源论坛替代自己开发社交模块,正好在开源中国上看到了一个利用discuz的UCenter功能实现同步登录的开源项目(https://code.google.com/p/discuz-ucenter-api-for-java/),不禁大喜,于是花了几个...

    JAVA与Discuz论坛整合中文用户名可登录

    最近在实现java项目对discuz的整合。 网上资料好多,大家可百度,google 现将java代码传上 需要修改config.properties配置信息 test.jsp中用自己账号及密码,中文名可登录 注:中文有问题可改 PHPFunctions类方法 ...

    discuz论坛插件DZ插件 发帖到微博多账号版

    《Discuz论坛插件:DZ插件-发帖到微博多账号版详解》 Discuz论坛插件,特别是这款“DZ插件-发帖到微博多账号版”,是针对Discuz论坛用户的一种增强工具,旨在提升社区互动性和社交媒体分享的便利性。这款插件的独特...

    discuz-ucenter_api_for_java(内附测试项目).rar

    discuz-ucenter_api_for_java(内附测试项目).rar,测试项目为discuz压缩包,把里面加压后, 1.导入到你的eclipse里面, 2.把论坛的密钥什么的直接配置在discuz的config.properties中, 3.修改test.java里面的登陆注册...

Global site tag (gtag.js) - Google Analytics