加入收藏 | 设为首页 | 会员中心 | 我要投稿 PHP编程网 - 黄冈站长网 (http://www.0713zz.com/)- 数据应用、建站、人体识别、智能机器人、语音技术!
当前位置: 首页 > 站长学院 > PHP教程 > 正文

解析PHP版单点登陆实现方案

发布时间:2022-03-31 23:45:03 所属栏目:PHP教程 来源:互联网
导读:本文主要介绍了利用webservice,session,cookie技术,来进行通用的单点登录系统的分析与设计。具体实现语言为PHP。单点登录,英文名为Single Sign On,简称为 SSO,是目前企业,网络业务的用户综合处理的重要组成部分。而SSO的定义,是在多个应用系统中,用
  本文主要介绍了利用webservice,session,cookie技术,来进行通用的单点登录系统的分析与设计。具体实现语言为PHP。单点登录,英文名为Single Sign On,简称为 SSO,是目前企业,网络业务的用户综合处理的重要组成部分。而SSO的定义,是在多个应用系统中,用户只需要登陆一次就可以访问所有相互信任的应用系统。
 
  动机:
 
  用过uctenter的全站登录方式的朋友,应该都知道这是典型的观察者模式的解决方案。用户中心作为subject, 其所属observer的注册和删除统一在ucenter的后台进行。而各个子应用站点都对应一个observer。每次用户中心的登录动作,都会触发js脚本回调w3c标准的子站登录接口(api/uc.php)。
 
  基于以上问题,在实际开发过程中,本人设计了另一套单点登录系统。
 
  一. 登陆原理说明
 
  单点登录的技术实现机制:当用户第一次访问应用系统1的时候,因为还没有登录,会被引导到认证系统中进行登录;根据用户提供的登录信息,认证系统进行身份效验,如果通过效验,应该返回给用户一个认证的凭据--ticket;用户再访问别的应用的时候,就会将这个ticket带上,作为自己认证的凭据,应用系统接受到请求之后会把ticket送到认证系统进行效验,检查ticket的合法性。如果通过效验,用户就可以在不用再次登录的情况下访问应用系统2和应用系统3了。
 
  可以看出,要实现SSO,需要以下主要的功能:
 
  a) 所有应用系统共享一个身份认证系统;
 
  b) 所有应用系统能够识别和提取ticket信息;
 
  c) 应用系统能够识别已经登录过的用户,能自动判断当前用户是否登录过,从而完成单点登录的功能
 
  基于以上基本原则,本人用php语言设计了一套单点登录系统的程序,目前已投入正式生成服务器运行。本系统程序,将ticket信息以全系统唯一的 session id作为媒介,从而获取当前在线用户的全站信息(登陆状态信息及其他需要处理的用户全站信息)。
 
  二. 过程说明:
 
  登陆流程:
 
  1. 第一次登陆某个站:
 
  a) 用户输入用户名+密码,向用户验证中心发送登录请求
 
  b) 当前登录站点,通过webservice请求,用户验证中心验证用户名,密码的合法性。如果验证通过,则生成ticket,用于标识当前会话的用户,并将当前登陆子站的站点标识符记录到用户中心,最后
 
  2. 登陆状态下,用户转到另一子:
 
  a) 通过本站cookie或session验证用户的登录状态:如验证通过,进入正常本站处理程序;否则户中心验证用户的登录状态(发送ticket到用户验证中心),如验证通过,则对返回的用户信息进行本地的登录处理,否则表明用户未登录。
 
  登出流程
 
  a) 当前登出站清除用户本站的登录状态 和 本地保存的用户全站唯一的随机id
 
  b) 通过webservice接口,清除全站记录的全站唯一的随机id。webservice接口会返回,登出其他已登录子站的javascript代码,本站输出此代码。
 
  c) js代码访问相应站W3C标准的登出脚本
 
  三. 代码说明:
 
  本文所涉及到相关代码,已打包上传,如有兴趣,可在本文最后下载链接处点击下载。
 
  1. 登陆流程:
 
  用户从打开浏览器开始,第一个登陆的子站点,必须调用UClientSSO::loginSSO()方法。该方法返回全站唯一的随机id用于标识该用户。该随机id在UClientSSO::loginSSO()中已通过本站cookie保存,即该子站点保留了用户已登陆标识的存根于本站。
 
             a) UClientSSO::loginSSO()方法如下:
  [php]/**
  * 用户验证中心 登陆用户处理
  *
  * @param string $username      - 用户名
  * @param string $password      - 用户原始密码
  * @param boolean $remember     - 是否永久记住登陆账号
  * @param boolean $alreadyEnc   - 传入的密码是否已经经过simpleEncPass加密过
  *
  * @return array   - integer $return['status'] 大于 0:返回用户 ID,表示用户登录成功
  *                                                -1:用户不存在,或者被删除
  *                                                -2:密码错
  *                                                                                                  -11:验证码错误
  *                                          string $return['username']     : 用户名
  *                                          string $return['password']     : 密码
  *                                          string $return['email']        : Email
  */
  static public function loginSSO($username, $password, $remember=false, $alreadyEnc=false) {
          self::_init();
          self::_removeLocalSid();
          $ret = array();
 
          //
          //1. 处理传入webservice接口的参数
          //
          $_params  = array(
                  'username' => $username,
                  'password' => $alreadyEnc ? trim($password) : self::simpleEncPass(trim($password)),
                  'ip'       => self::onlineip(),
                  'siteFlag' => self::$site,
                  'remember' => $remember
          );
          $_params['checksum'] = self::_getCheckSum($_params['username'] . $_params['password'] .
                  $_params['ip'] . $_params['siteFlag'] . $_params['remember']);
 
          //
          // 2.调用webservice接口,进行登陆处理
          //
          $aRet = self::_callSoap('loginUCenter', $_params);
 
          if (intval($aRet['resultFlag']) > 0 && $aRet['sessID']) {
                  //成功登陆
                  //设置本地session id
                  self::_setLocalSid($aRet['sessID']);
 
                  //设置用户中心的统一session id脚本路径
                  self::$_synloginScript = urldecode($aRet['script']);
 
                  $ret = $aRet['userinfo'];
          } else {
 
                  $ret['status'] = $aRet['resultFlag'];
          }
 
          return $ret;
  }//end of function                   [/php]
 
           b) 用户验证中心的webservice服务程序,接收到登陆验证请求后,调用UCenter::loginUCenter()方法来处理登陆请求。
  [php]/**
  * 用户验证中心 登陆用户处理
  *
  * @param string $username
  * @param string $password
  * @param string $ip
  * @param string $checksum
  * @return array
  */
  static public function loginUCenter($username, $password, $ip, $siteFlag, $remember=false) {
          self::_init();
          session_start();
          $ret = array();
          $arr_login_res     = login_user($username, $password, $ip);
          $res_login         = $arr_login_res['status'];                //
          $ret['resultFlag'] = $res_login;
 
          if ($res_login < 1) {
                  //登陆失败
          } else {
 
                  //登陆成功
                  $_SESSION[self::$_ucSessKey] = $arr_login_res;
 
                  $_SESSION[self::$_ucSessKey]['salt'] =
                          self::_getUserPassSalt($_SESSION[self::$_ucSessKey]['username'], $_SESSION[self::$_ucSessKey]['password']);
 
                  $ret['userinfo'] = $_SESSION[self::$_ucSessKey];
                  $ret['sessID']   = session_id();        //生成全站的唯一session id,作为ticket全站通行
 
                  //
                  //合作中心站回调登陆接口(设置用户中心的统一session id)
                  //
                  self::_createCoSitesInfo();
                  $uinfo = array();
                  $_timestamp = time();
                  $_rawCode = array(
                          'action' => 'setSid',
                          'sid'    => $ret['sessID'],
                          'time'   => $_timestamp,
                  );
                  if ($remember) {
                          $uinfo = array(
                                  'remember' => 1,
                                  'username' => $username,
                                  'password' => $password
                          );
                  }
 
                  $ret['script'] = '';
                  $_rawStr = http_build_query(array_merge($_rawCode, $uinfo));
 
                  //
                  // 合作站点的全域cookie设置脚本地址
                  //
                  foreach ((array)self::$_coSitesInfo as $_siteInfo) {
                          $_code = self::authcode($_rawStr, 'ENCODE', $_siteInfo['key']);
                          $_src = $_siteInfo['url'] . '?code=' . $_code . '&time=' . $_timestamp;
                          $ret['script'] .= urlencode('');
                  }
 
                  //
                  // 记住已登陆战
                  //
                  self::registerLoggedSite($siteFlag, $ret['sessID']);
 
                  unset($ret['userinfo']['salt']);
          }
 
          return $ret;
  }         [/php]
 
          2. 本站登陆成功后,进行本地化的用户登陆处理,其后验证用户是否登陆只在本地验证。(本地存取登陆用户状态的信息,请设置为关闭浏览器就退出)
 
          3. 当检测用户登陆状态时,请先调用本地的验证处理,若本地验证不通过,再调用UClientSSO::checkUserLogin()方法到用户中心检测用户的登陆状态。 a) UClientSSO::checkUserLogin()方法如下:
  [php]/**
  * 用户单点登陆验证函数
  *
  * @return array   - integer $return['status'] 大于 0:返回用户 ID,表示用户登录成功
  *                                                                                                    0:用户没有在全站登陆
  *                                                -1:用户不存在,或者被删除
  *                                                -2:密码错
  *                                                -3:未进行过单点登陆处理
  *                                                                                                  -11:验证码错误
  *                                          string $return['username']     : 用户名
  *                                          string $return['password']     : 密码
  *                                          string $return['email']        : Email
  */

(编辑:PHP编程网 - 黄冈站长网)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    热点阅读