本篇文章主要介紹了PHP版單點登陸實現方案的實例,具有一定的參考價值,有需要的可以了解一下。
摘要:
本文主要介紹了利用webservice,session,cookie技術,來進行通用的單一登入系統的分析與設計。具體實作語言為PHP。單點 登錄,英文名為Single Sign On,簡稱 SSO,是目前企業,網絡業務的用戶綜合處理的重要組成部分。而SSO的定義,是在多個應用系統中,使用者只需要登陸一次就可以存取所有互信的應用系 統。
動機:
用過ucenter的全站登入方式的朋友,應該都知道這是典型的觀察者模式的解決方案。用戶中心作為subject, 其所屬observer的註冊和刪除統一在ucenter的後台進行。而各個子應用程式站點都對應一個observer。每次使用者中心的登入動作,都會觸發 js腳本回呼w3c標準的子站登入介面(api/uc.php)。
這種方式的缺點,本人認為主要是兩點:1. 子站點過多時,回調接口相應增多,這個在分佈子站的量的限制上,如何控制來使登錄效率不會太低,不好把握; 2. 當某個子站回調介面出現問題時,預設的登入程序會卡住(可以限制登入程序的執行時間,但對應出現問題子站後面的子站的回呼介面就調不到了。
基於上述問題,在實際開發過程中,本人設計了另一套單一登入系統。
##一.登陸原理說明
##單點登錄的技術實現機制:當用戶第一次訪問應用系統1的時候,因為還沒有登錄,會被引導到認證系統中進行登錄;根據用戶提供的登錄信息,認證系統進行身份效驗,如果通過效驗,應該返回給用戶一個認證的憑證--ticket;用戶再訪問別的應用的時候,就會將這個ticket帶上,作為自己認證的憑據,應用系統接受到請求之後會把ticket送到認證系統進行效驗,檢查ticket的合法性。如果透過效驗,使用者就可以在不用再登入的情況下存取應用系統2和應用系統3了。可以看出,要實現SSO,需要以下主要的功能:a) 所有應用系統共享一個身份認證系統;b) 所有應用系統能夠識別和提取ticket資訊;c) 應用系統能夠辨識已登入的用戶,能自動判斷目前使用者是否登入過,從而完成單一登入的功能
#基於以上基本原則,本人用php語言設計了一套單一登入系統的程序,目前已投入正式生成伺服器運作。本系統程序,將ticket資訊以全系統唯一的 session id作為媒介,從而取得目前線上使用者的全站資訊(登陸狀態資訊及其他所需要處理的使用者全站資訊)。二. 流程說明:
登陸流程:#1. 第一次登陸某個站:a)使用者輸入使用者名稱密碼,向使用者驗證中心發送登入請求b) 目前登入站點,透過webservice請求,使用者驗證中心驗證使用者名,密碼的合法性。如果驗證通過,則產生ticket,用於標識目前會話的用戶,並將目前登陸子站的網站識別碼記錄到用戶中心,最後c) 將取得的用戶資料和ticket傳回給子站。如果驗證不通過,則傳回對應的錯誤狀態碼。 d) 根據上一步的webservice請求返回的結果,當前子站對用戶進行登陸處理:如狀態碼表示成功的話,則當前站點通過本站cookie保存ticket,並本站記錄用戶的登入狀態。狀態碼表示失敗的話,則給使用者對應的登入失敗提示。2. 登陸狀態下,使用者前往另一子:
a) 透過本站cookie或session驗證使用者的登入狀態:如驗證通過,進入正常本站處理程序;否則戶中心驗證使用者的登入狀態(發送ticket到使用者驗證中心),如驗證通過,則對傳回的使用者資訊進行本機的登入處理,否則表示使用者未登入。登出流程
a) 目前登出站清除使用者本站的登入狀態和本機儲存的使用者全站唯一的隨機idb) 透過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 //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['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; } ?>#######
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 */ 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('|g|', self::authcode($_COOKIE[_UC_USER_COOKIE_NAME], 'DECODE', self::$_authcodeKey)); $username = $_userinfo[0]; $password = isset($_userinfo[1]) ? $_userinfo[1] : ''; if (empty($password)) { $ret['status'] = -3; } else { return self::loginSSO($username, $password, true, true); } } else { $ret['status'] = -3; } } else { // //本站原先已经登陆过,通过保留的sesson id存根去用户中心验证 // $_params = array( 'sessId' => $_sessId, 'siteFlag' => self::$site, 'checksum' => md5($_sessId . self::$site . self::$_mcComunicationKey) ); $aRet = self::_callSoap('getOnlineUser', $_params); if (intval($aRet['resultFlag']) > 0) { //成功登陆 $ret = $aRet['userinfo']; } else { $ret['status'] = $aRet['resultFlag']; } } 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['username']) && isset($_userinfo['password']) && self::_getUserPassSalt($_userinfo['username'], $_userinfo['password'])) { $ret['resultFlag'] = "1"; $ret['userinfo'] = $_userinfo; self::registerLoggedSite($siteFlag, $sessId); //记住已登陆战 unset($ret['userinfo']['salt']); } else { $ret['resultFlag'] = "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( 'sessId' => $_sessId, 'siteFlag' => self::$site, 'checksum' => md5($_sessId . self::$site . self::$_mcComunicationKey) ); $aRet = self::_callSoap('logoutUCenter', $_params); if (intval($aRet['resultFlag']) > 0) { //成功登出 self::_removeLocalSid(); //移除本站记录的sid存根 self::$_synlogoutScript = urldecode($aRet['script']); $ret = 1; } else { $ret = $aRet['resultFlag']; } 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('session.auto_start', 0); //关闭session自动启动 ini_set('session.cookie_lifetime', 0); //设置session在浏览器关闭时失效 ini_set('session.gc_maxlifetime', 3600); //session在浏览器未关闭时的持续存活时间 ?>
b) cookie方式记录用户登陆状态的站点
请在设置用户登陆状态的cookie时,设置cookie有效时间为null.
原文链接:http://www.cnblogs.com/linzhenjie/archive/2012/08/24/2653585.html
以上就是本文的全部内容,希望对大家的学习有所帮助。
相关推荐:
#
以上是PHP版單點登陸實現方案的詳細內容。更多資訊請關注PHP中文網其他相關文章!

PHP在現代Web開發中仍然重要,尤其在內容管理和電子商務平台。 1)PHP擁有豐富的生態系統和強大框架支持,如Laravel和Symfony。 2)性能優化可通過OPcache和Nginx實現。 3)PHP8.0引入JIT編譯器,提升性能。 4)雲原生應用通過Docker和Kubernetes部署,提高靈活性和可擴展性。

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP和Python各有優勢,適合不同場景。 1.PHP適用於web開發,提供內置web服務器和豐富函數庫。 2.Python適合數據科學和機器學習,語法簡潔且有強大標準庫。選擇時應根據項目需求決定。

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP成為許多網站首選技術棧的原因包括其易用性、強大社區支持和廣泛應用。 1)易於學習和使用,適合初學者。 2)擁有龐大的開發者社區,資源豐富。 3)廣泛應用於WordPress、Drupal等平台。 4)與Web服務器緊密集成,簡化開發部署。

PHP在現代編程中仍然是一個強大且廣泛使用的工具,尤其在web開發領域。 1)PHP易用且與數據庫集成無縫,是許多開發者的首選。 2)它支持動態內容生成和麵向對象編程,適合快速創建和維護網站。 3)PHP的性能可以通過緩存和優化數據庫查詢來提升,其廣泛的社區和豐富生態系統使其在當今技術棧中仍具重要地位。

在PHP中,弱引用是通過WeakReference類實現的,不會阻止垃圾回收器回收對象。弱引用適用於緩存系統和事件監聽器等場景,需注意其不能保證對象存活,且垃圾回收可能延遲。

\_\_invoke方法允許對象像函數一樣被調用。 1.定義\_\_invoke方法使對象可被調用。 2.使用$obj(...)語法時,PHP會執行\_\_invoke方法。 3.適用於日誌記錄和計算器等場景,提高代碼靈活性和可讀性。


熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

AI Hentai Generator
免費產生 AI 無盡。

熱門文章

熱工具

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver Mac版
視覺化網頁開發工具

WebStorm Mac版
好用的JavaScript開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

mPDF
mPDF是一個PHP庫,可以從UTF-8編碼的HTML產生PDF檔案。原作者Ian Back編寫mPDF以從他的網站上「即時」輸出PDF文件,並處理不同的語言。與原始腳本如HTML2FPDF相比,它的速度較慢,並且在使用Unicode字體時產生的檔案較大,但支援CSS樣式等,並進行了大量增強。支援幾乎所有語言,包括RTL(阿拉伯語和希伯來語)和CJK(中日韓)。支援嵌套的區塊級元素(如P、DIV),