>백엔드 개발 >PHP 튜토리얼 >PHP 버전 싱글 로그인 구현 솔루션

PHP 버전 싱글 로그인 구현 솔루션

墨辰丷
墨辰丷원래의
2018-05-30 17:13:421721검색

이 글에서는 싱글 로그인 구현 솔루션의 PHP 버전에 대한 예제를 주로 소개합니다. 필요한 경우 자세히 알아볼 수 있습니다.

요약:

이 기사에서는 주로 웹 서비스, 세션 및 쿠키 기술을 사용하는 범용 싱글 사인온 시스템의 분석 및 설계를 소개합니다. 구체적인 구현 언어는 PHP입니다. 영어로 Single Sign On, 줄여서 SSO라고도 하는 Single Sign-On은 현재 기업과 네트워크 비즈니스에서 사용자를 포괄적으로 처리하는 데 중요한 부분입니다. SSO의 정의는 여러 응용 프로그램 시스템에서 사용자가 한 번만 로그인하면 상호 신뢰되는 모든 응용 프로그램 시스템에 액세스할 수 있다는 것입니다.

동기:

ucenter의 전체 사이트 로그인 방법을 사용해 본 친구들은 이것이 전형적인 관찰자 패턴 솔루션이라는 것을 알아야 합니다. 사용자 센터는 주체이며 관찰자의 등록 및 삭제는 ucenter 백엔드에서 통합됩니다. 각 하위 응용 프로그램 사이트는 관찰자에 해당합니다. 사용자 센터의 모든 로그인 작업은 js 스크립트를 트리거하여 w3c 표준 하위 사이트 로그인 인터페이스(api/uc.php)를 다시 호출합니다.

이 방법의 단점은 주로 두 가지라고 생각합니다. 1. 하위 사이트가 너무 많으면 그에 따라 콜백 인터페이스가 증가합니다. 이는 분산된 하위 사이트 수에 따라 제한됩니다. 2. 특정 변전소의 콜백 인터페이스에 문제가 있으면 기본 로그인 프로세스가 중단됩니다(로그인 프로그램의 실행 시간이 제한될 수 있음). 하지만 해당 변전소 뒤에 있는 변전소의 콜백 인터페이스는 조정할 수 없습니다.

위 문제를 토대로 실제 개발 과정에서 또 다른 Single Sign-On 시스템을 설계했습니다.

1. 로그인 원리 설명

기술적 구현 Single Sign-On 메커니즘: 사용자가 처음으로 응용 프로그램 시스템에 액세스할 때 1. 이때 아직 로그인하지 않았으므로 제공된 로그인 정보를 기반으로 로그인할 수 있는 인증 시스템으로 이동하게 됩니다. 사용자가 인증 시스템에서 신원 확인을 수행하면 인증 자격 증명을 반환해야 합니다. 사용자가 다시 방문하면 이 티켓이 자체 자격 증명으로 제공됩니다. 요청을 받은 후 신청 시스템은 확인을 위해 티켓을 인증 시스템으로 보냅니다. 티켓의 유효성이 확인을 통과하면 사용자는 다시 로그인하지 않고도 신청 시스템 2와 신청 시스템 3에 액세스할 수 있습니다.

SSO를 구현하려면 다음과 같은 주요 기능이 필요함을 알 수 있습니다.

a) 모든 신청 시스템은 신원 인증 시스템을 공유합니다.

b) 신청 시스템은 모두 티켓 정보를 식별하고 추출할 수 있습니다.

c ) 응용 프로그램 시스템은 로그인한 사용자를 식별할 수 있고, 현재 사용자가 로그인했는지 여부를 자동으로 판단하여 싱글 로그인 기능을 완료할 수 있습니다

위의 기본 원칙을 바탕으로 저는 PHP 언어를 사용합니다. 싱글 사인 세트 -on 시스템 절차는 공식적으로 서버를 생성하기 위해 설계되고 실행되었습니다. 이 시스템 프로그램은 전체 시스템의 고유한 세션 ID를 가진 티켓 정보를 매체로 사용하여 현재 온라인 사용자의 전체 사이트 정보(로그인 상태 정보 및 기타 처리해야 할 사용자 전체 사이트 정보)를 얻습니다.

2. 프로세스 설명:

로그인 프로세스:

1. 사이트에 처음 로그인:

a) 사용자가 사용자 이름 + 비밀번호를 입력하고 사용자 인증 센터에 로그인 요청을 보냅니다.

b) 현재 로그인 사이트에서는 웹 서비스 요청을 통해 사용자 인증 센터에서 사용자 이름과 비밀번호의 적법성을 확인합니다. 검증에 성공하면 현재 세션의 사용자를 식별하기 위한 티켓이 생성되고, 현재 로그인된 하위 사이트의 사이트 식별자가 사용자 센터에 기록됩니다. 마지막으로

c) 획득한 사용자 데이터를 반환하고 하위 사이트 티켓. 확인에 실패하면 해당 오류 상태 코드가 반환됩니다.

d) 이전 단계의 웹 서비스 요청에서 반환된 결과에 따라 현재 하위 사이트는 사용자에 로그인합니다. 상태 코드가 성공을 나타내면 현재 사이트는 이 사이트의 쿠키를 통해 티켓을 저장하고 기록합니다. 사용자의 로그인 상태. 상태 코드가 실패를 나타내는 경우 사용자에게 해당 로그인 실패 프롬프트가 표시됩니다.

2. 로그인하면 사용자가 다른 페이지로 이동합니다.

a) 사이트의 쿠키 또는 세션을 통해 사용자의 로그인 상태를 확인합니다. 확인이 통과되면 일반 사이트 처리 프로그램에 들어가고 그렇지 않으면 사용자 센터에서 확인합니다. 사용자의 로그인 상태(사용자 인증 센터로 티켓 보내기), 인증에 성공하면 반환된 사용자 정보가 로컬로 로그인됩니다. 그렇지 않으면 사용자가 로그인되지 않은 것입니다.

로그아웃 프로세스

a) 현재 로그아웃은 사이트의 사용자 로그인 상태와 로컬에 저장된 사용자의 전체 사이트의 고유 랜덤 ID를 삭제합니다.

b) 웹 서비스 인터페이스를 통해 전체 사이트의 고유 랜덤 ID를 삭제합니다. 사이트 전체가 기록하는 사이트 Random id. 웹 서비스 인터페이스가 반환되고 로그인된 다른 하위 사이트의 자바스크립트 코드가 로그아웃되며 이 사이트에서 이 코드가 출력됩니다.

c) js 코드는 해당 사이트의 W3C 표준 로그아웃 스크립트에 액세스합니다.

3. 코드 설명:

이 기사에 관련된 관련 코드가 패키지되어 업로드되어 있습니다. 관심이 있으시면 클릭하여 다운로드하실 수 있습니다. 이 기사의 마지막 다운로드 링크에서.

1. 로그인 프로세스:

브라우저를 열 때부터 로그인한 첫 번째 하위 사이트는 UClientSSO::loginSSO() 메서드를 호출해야 합니다. 이 방법은 전체 사이트에 고유하고 사용자를 식별하는 데 사용되는 임의의 ID를 반환합니다. 이 임의 ID는 이 사이트의 쿠키를 통해 UClientSSO::loginSSO()에 저장되었습니다. 즉, 하위 사이트는 이 사이트에 대한 사용자 로그인 ID의 스텁을 유지합니다.

a) UClientSSO::loginSSO() 메소드는 다음과 같습니다:

 <?php
/**
 * 用户验证中心 登陆用户处理
 *
 * @param string $username   - 用户名
 * @param string $password   - 用户原始密码
 * @param boolean $remember   - 是否永久记住登陆账号
 * @param boolean $alreadyEnc  - 传入的密码是否已经经过simpleEncPass加密过
 *
 * @return array  - integer $return[&#39;status&#39;] 大于 0:返回用户 ID,表示用户登录成功
 *                        -1:用户不存在,或者被删除
 *                        -2:密码错
 *                                                 -11:验证码错误
 *                     string $return[&#39;username&#39;]   : 用户名
 *                     string $return[&#39;password&#39;]   : 密码
 *                     string $return[&#39;email&#39;]    : Email
 */

static public function loginSSO($username, $password, $remember=false, $alreadyEnc=false) {
self::_init();
self::_removeLocalSid();
$ret = array();

//
//1. 处理传入webservice接口的参数
//
$_params = array(
        &#39;username&#39; => $username,
        &#39;password&#39; => $alreadyEnc ? trim($password) : self::simpleEncPass(trim($password)),
        &#39;ip&#39;    => self::onlineip(),
        &#39;siteFlag&#39; => self::$site,
        &#39;remember&#39; => $remember
);
$_params[&#39;checksum&#39;] = self::_getCheckSum($_params[&#39;username&#39;] . $_params[&#39;password&#39;] .
$_params[&#39;ip&#39;] . $_params[&#39;siteFlag&#39;] . $_params[&#39;remember&#39;]);

//
// 2.调用webservice接口,进行登陆处理
//
$aRet = self::_callSoap(&#39;loginUCenter&#39;, $_params);

if (intval($aRet[&#39;resultFlag&#39;]) > 0 && $aRet[&#39;sessID&#39;]) {
//成功登陆
//设置本地session id
self::_setLocalSid($aRet[&#39;sessID&#39;]);

//设置用户中心的统一session id脚本路径
self::$_synloginScript = urldecode($aRet[&#39;script&#39;]);

$ret = $aRet[&#39;userinfo&#39;];
} else {

$ret[&#39;status&#39;] = $aRet[&#39;resultFlag&#39;];
}

return $ret;
}//end of function         

//b) 用户验证中心的webservice服务程序,接收到登陆验证请求后,调用UCenter::loginUCenter()方法来处理登陆请求。
/**
* 用户验证中心 登陆用户处理
*
* @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[&#39;status&#39;];        //
$ret[&#39;resultFlag&#39;] = $res_login;

if ($res_login < 1) {
//登陆失败
} else {

//登陆成功
$_SESSION[self::$_ucSessKey] = $arr_login_res;

$_SESSION[self::$_ucSessKey][&#39;salt&#39;] =
self::_getUserPassSalt($_SESSION[self::$_ucSessKey][&#39;username&#39;], $_SESSION[self::$_ucSessKey][&#39;password&#39;]);

$ret[&#39;userinfo&#39;] = $_SESSION[self::$_ucSessKey];
$ret[&#39;sessID&#39;]  = session_id();    //生成全站的唯一session id,作为ticket全站通行

//
//合作中心站回调登陆接口(设置用户中心的统一session id)
//
self::_createCoSitesInfo();
$uinfo = array();
$_timestamp = time();
$_rawCode = array(
            &#39;action&#39; => &#39;setSid&#39;,
            &#39;sid&#39;  => $ret[&#39;sessID&#39;],
            &#39;time&#39;  => $_timestamp,
);
if ($remember) {
$uinfo = array(
                &#39;remember&#39; => 1,
                &#39;username&#39; => $username,
                &#39;password&#39; => $password
);
}

$ret[&#39;script&#39;] = &#39;&#39;;
$_rawStr = http_build_query(array_merge($_rawCode, $uinfo));

//
// 合作站点的全域cookie设置脚本地址
//
foreach ((array)self::$_coSitesInfo as $_siteInfo) {
$_code = self::authcode($_rawStr, &#39;ENCODE&#39;, $_siteInfo[&#39;key&#39;]);
$_src = $_siteInfo[&#39;url&#39;] . &#39;?code=&#39; . $_code . &#39;&time=&#39; . $_timestamp;
$ret[&#39;script&#39;] .= urlencode(&#39;&#39;);
}

//
// 记住已登陆战
//
self::registerLoggedSite($siteFlag, $ret[&#39;sessID&#39;]);

unset($ret[&#39;userinfo&#39;][&#39;salt&#39;]);
}

return $ret;
}

?>

2. 本站登陆成功后,进行本地化的用户登陆处理,其后验证用户是否登陆只在本地验证。(本地存取登陆用户状态的信息,请设置为关闭浏览器就退出)

 3. 当检测用户登陆状态时,请先调用本地的验证处理,若本地验证不通过,再调用UClientSSO::checkUserLogin()方法到用户中心检测用户的登陆状态。

a) UClientSSO::checkUserLogin()方法如下:

 <?php
 /**
 * 用户单点登陆验证函数
 *
 * @return array  - integer $return[&#39;status&#39;] 大于 0:返回用户 ID,表示用户登录成功
 *                                                  0:用户没有在全站登陆
 *                        -1:用户不存在,或者被删除
 *                        -2:密码错
 *                        -3:未进行过单点登陆处理
 *                                                 -11:验证码错误
 *                     string $return[&#39;username&#39;]   : 用户名
 *                     string $return[&#39;password&#39;]   : 密码
 *                     string $return[&#39;email&#39;]    : Email
 */
 public static function checkUserLogin(){
 self::_init();
 $ret = array();
 $_sessId = self::_getLocalSid();
 if (empty($_sessId)) {
 //永久记住账号处理
 if(isset($_COOKIE[_UC_USER_COOKIE_NAME]) && !empty($_COOKIE[_UC_USER_COOKIE_NAME])) {
 
 //
 // 根据cookie里的用户名和密码判断用户是否已经登陆。
 //
 $_userinfo = explode(&#39;|g|&#39;, self::authcode($_COOKIE[_UC_USER_COOKIE_NAME], &#39;DECODE&#39;, self::$_authcodeKey));
 
 $username = $_userinfo[0];
 $password = isset($_userinfo[1]) ? $_userinfo[1] : &#39;&#39;;
 if (empty($password)) {
 $ret[&#39;status&#39;] = -3;
 } else {
 return self::loginSSO($username, $password, true, true);
 }
 
 } else {
 $ret[&#39;status&#39;] = -3;
 }
 
 } else {
 //
 //本站原先已经登陆过,通过保留的sesson id存根去用户中心验证
 //
 $_params = array(
             &#39;sessId&#39;  => $_sessId,
             &#39;siteFlag&#39; => self::$site,
             &#39;checksum&#39; => md5($_sessId . self::$site . self::$_mcComunicationKey)
 );
 $aRet = self::_callSoap(&#39;getOnlineUser&#39;, $_params);
 if (intval($aRet[&#39;resultFlag&#39;]) > 0) {
 //成功登陆
 $ret = $aRet[&#39;userinfo&#39;];
 } else {
 $ret[&#39;status&#39;] = $aRet[&#39;resultFlag&#39;];
 }
 }
 
 return $ret;
 }       
 
 b) 用户验证中心的webservice服务程序,接收到检验登陆的请求后,调用UCenter::getOnlineUser()方法来处理登陆请求:
 [php]/**
 * 根据sid,获取当前登陆的用户信息
 *
 * @param string $sessId    - 全站唯一session id,用做ticket
 * @return array
 */
 /**
 * 根据sid,获取当前登陆的用户信息
 *
 * @param string $sessId    - 全站唯一session id,用做ticket
 * @return array
 */
 static public function getOnlineUser($sessId, $siteFlag) {
 self::_init();
 session_id(trim($sessId));
 session_start();
 
 $ret = array();
 $_userinfo = $_SESSION[self::$_ucSessKey];
 
 if (isset($_userinfo[&#39;username&#39;]) && isset($_userinfo[&#39;password&#39;]) &&
 self::_getUserPassSalt($_userinfo[&#39;username&#39;], $_userinfo[&#39;password&#39;])) {
 $ret[&#39;resultFlag&#39;] = "1";
 $ret[&#39;userinfo&#39;] = $_userinfo;
 
 self::registerLoggedSite($siteFlag, $sessId);        //记住已登陆战
 unset($ret[&#39;userinfo&#39;][&#39;salt&#39;]);
 } else {
 $ret[&#39;resultFlag&#39;] = "0";
 }
 
 return ($ret);
 }
 ?>

 4. 单点登出时,调用UClientSSO::logoutSSO()方法。调用成功后,如需其他已登陆站立即登出,请调用 UClientSSO::getSynloginScript()方法获取W3C标准的script,在页面输出。

a) UClientSSO::logoutSSO()方法如下:        

<?php
/**
* 全站单点登出
* - 通过webservice请求注销掉用户的全站唯一标识
*
* @return integer  1: 成功
*                   -11:验证码错误
*/
public static function logoutSSO(){
    self::_init();
    $_sessId = self::_getLocalSid();
    //
    //本站没有登陆的话,不让同步登出其他站
    //
    if (empty($_sessId)) {
        self::_initSess(true);
        return false;
    }
    $_params = array(
        &#39;sessId&#39;  => $_sessId,
        &#39;siteFlag&#39; => self::$site,
        &#39;checksum&#39; => md5($_sessId . self::$site . self::$_mcComunicationKey)
    );
    $aRet = self::_callSoap(&#39;logoutUCenter&#39;, $_params);
    if (intval($aRet[&#39;resultFlag&#39;]) > 0) {
        //成功登出
        self::_removeLocalSid();        //移除本站记录的sid存根
        self::$_synlogoutScript = urldecode($aRet[&#39;script&#39;]);
        $ret = 1;
    } else {
        $ret = $aRet[&#39;resultFlag&#39;];
    }
    return intval($ret);
}          [/php]
    b) 用户验证中心的webservice服务程序,接收到全站登出请求后,调用UCenter::loginUCenter()方法来处理登陆请求:
/**
* 登出全站处理
*
* @param string - 全站唯一session id,用做ticket
* @return boolean
*/
static public function logoutUCenter($sessId) {
    self::_init();
    session_id(trim($sessId));
    session_start();
    $_SESSION = array();
    return empty($_SESSION) ? true : false;
}
?>

四. 代码部署:         

1. 用户验证中心设置                 

a) 用户验证中心向分站提供的webservice服务接口文件,即UserSvc.php部署在hostname/webapps/port/ UserSvc.php中。查看wsdl内容,请访问https://hostname/port/ UserSvc.php?wsdl

 b) 用户中心用户单点服务类文件为UCenterSSO.class.php,文件路径为在hostname/webapps/include /UCenterSSO.class.php。该文件为用户单点登陆处理 的服务端类,被hostname/webapps/port/ UserSvc.php调用。用于获取用户的登陆信息,是否单点登陆的状态信息,单点登出处理等。

 c) 用户验证中心通过W3C标准,利用cookie方式记录,删除全站统一的用户唯一随机id 的脚本文件为hostname/webapps/port/cookie_mgr.php.

2. 子站点设置                 

a) 各子站点请将,UClientSSO.class.php部署在用户中心服务客户端目录下。部署好后,请修改最后一行的UClientSSO::setSite('1'); 参数值为用户验证中心统一分配给各站的标识id.

b) 在部署的用户中心服务客户端包下的api目录下下,请将logout_sso.php脚本转移到此处,并编写进行本站登出的处理脚本。

c) 在子站点验证用户登陆状态的代码部分,额外增加到用户中心的单点登陆验证的处理。

即在首先通过本站验证用户的登陆状态,如果未通过验证,则去用户中心验证。验证操作要调用UClientSSO::checkUserLogin();接口,接口含义请查看代码注释。

d) 在分站的登出处理脚本中,通过UClientSSO::getSynlogoutScript();获取script串输出即可。

五. 扩展功能:       

1. 记录跟踪所有在线用户

因为所有用户的登录都要经过用户验证中心,所有用户的ticket都在验证中心生成,可以将用户和该ticket(session id)在内存表中建立一个映射表。得到所有在线用户的记录表。

后期如有必要跟踪用户状态来实现其他功能,只要跟踪这个映射表就可以了。其他功能可以为: 获取在线用户列表,判断用户在线状态,获取在线用户人数等。

 2. 特殊统计处理

因为整个系统登录登出要经过用户验证中心,所以可以针对用户的特殊统计进行处理。如用户每天的登录次数,登陆时间,登陆状态失效时间,各时段的在线用户人数走势等。

六. 其他事项:       

1. 本站登陆状态有效时间问题:                  

全站要求用户登陆状态在关闭浏览器时就失效。要求各分站对session或cookie的处理方式按照如下进行:

a) Session方式记录用户登陆状态的站点

请在站点公用脚本开始处,添加一下代码

 <?php
 session_write_close();
 ini_set(&#39;session.auto_start&#39;, 0);          //关闭session自动启动
 ini_set(&#39;session.cookie_lifetime&#39;, 0);      //设置session在浏览器关闭时失效
 ini_set(&#39;session.gc_maxlifetime&#39;, 3600); //session在浏览器未关闭时的持续存活时间   
 ?>

b) cookie方式记录用户登陆状态的站点

请在设置用户登陆状态的cookie时,设置cookie有效时间为null.

原文链接:http://www.cnblogs.com/linzhenjie/archive/2012/08/24/2653585.html

以上就是本文的全部内容,希望对大家的学习有所帮助。


相关推荐:

PHP数组分类、数组创建实例讲解

php pdo占位符的使用(代码实例讲解)

PHP 다차원 배열 정렬 배열에 대한 자세한 설명

위 내용은 PHP 버전 싱글 로그인 구현 솔루션의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.