為PHPBB加一個oauth認證方式統(tǒng)一登陸SSO tag:phpbb,sso,統(tǒng)一登陸,oauth2,oauth 以下文章只是講述我做這個東西的一個原理,主要實現(xiàn)是采用主站的認證來實現(xiàn)本站點的登陸,論壇采用隱式的密碼認證方式;如果想要了解更多,可以聯(lián)系我caijiche@gmail.com;這是www.用于oauth的原理。發(fā)出來和大家一起分享! 操作步驟 一、將auth_oauth2.php加入論壇的includes/auth/這個目錄當中,這是一個OAUTH的插件,使其支持這種認證方式二、將caijicheOauthClient.php這個文件加入PHPBB的根目錄中,這個文件是CAIJICHE的oauth客戶端文件; 三、將論壇的數(shù)據(jù)庫bbs_config表中的auth_method的值改成“oauth2”,說明使用oauth2認證; 四、為了使后臺管理員也可以使用這種認證方式,把functions.php中的以下這段注釋掉 if ($admin && utf8_clean_string($username) != utf8_clean_string($user->data['username'])) { // We log the attempt to use a different username... add_log('admin', 'LOG_ADMIN_AUTH_FAIL'); trigger_error('NO_AUTH_ADMIN_USER_DIFFER'); } 否則會報不匹配的錯誤; 五、更改注冊鏈接: 將functions.php中的函數(shù)page_header中的數(shù)組中“U_REGISTER”的值改成“http://www./reg” 六、更改忘記密碼鏈接:將functions.php中的函數(shù)page_header中的數(shù)組中“ U_SEND_PASSWORD ”的值改成“http://www./getpwd” phpbb報一些警告錯誤的解決辦法: 將對應的函數(shù)改成靜態(tài)函數(shù) 七、語言文件:"登錄" 改成 "使用采集車賬號登陸" "用戶名(USERNAME)"改成 "用戶名[email]" 以下是auth_oauth2.php的內(nèi)容 這個文件主要還是參考auth_db.php簡單改動了一下 <?php /** * Database auth plug-in for phpBB3 * * Authentication plug-ins is largely down to Sergey Kanareykin, our thanks to him. * * This is for authentication via the integrated user table * * @package login * @version $Id: auth_db.php 10431 2010-01-20 00:20:46Z bantu $ * @copyright (c) 2005 phpBB Group * @license http:///licenses/gpl-license.php GNU Public License * */ /** * @ignore */ if (!defined('IN_PHPBB')) { exit; } /** * Login function */ function login_oauth2(&$username, &$password) { global $db, $config,$phpbb_root_path; include ($phpbb_root_path . 'caijicheOauthClient.php');//將客戶端的類含進來 require_once($phpbb_root_path.'common.php'); require_once($phpbb_root_path.'includes/functions_user.php'); // require_once($phpbb_root_path.'includes/functions_module.php'); // 密碼為空 if (!$password) { return array( 'status' => LOGIN_ERROR_PASSWORD, 'error_msg' => 'NO_PASSWORD_SUPPLIED', 'user_row' => array('user_id' => ANONYMOUS), ); } //用戶名為空 if (!$username) { return array( 'status' => LOGIN_ERROR_USERNAME, 'error_msg' => 'LOGIN_ERROR_USERNAME', 'user_row' => array('user_id' => ANONYMOUS), ); } $client_config = array( 'client_id' => "3c2d81228736786e5e846fewqrewqrfedsfadsafre", 'client_secret' => "f6996b15ewqrewqt434f4342e237abf4" ); $client = new CaijicheOAuthClient($client_config); //$par['username'] = "caijiche@gmail.com"; //$par['password'] = '$caijiche$'; $par['username'] = $username; $par['password'] = $password; $o_url = $client->getAccessToken($par,'password'); //var_dump($o_url); if(isset($o_url['access_token'])){ $caijiche_user = $client->getUserInfo($o_url['access_token']); // var_dump($caijiche_user); } $password='$www.CAIJICHE.com';//在這里更換用戶的用戶名和密碼 $username=$caijiche_user['user_nick']; $useremail=$caijiche_user['user_email'];//用戶郵箱 $sql = 'SELECT user_id, username, user_password, user_passchg, user_pass_convert, user_email, user_type, user_login_attempts FROM ' . USERS_TABLE . " WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); if (!$row) { $timezone = date('Z') / 3600; $is_dst = date('I'); if ($config['board_timezone'] == $timezone || $config['board_timezone'] == ($timezone - 1)) { $timezone = ($is_dst) ? $timezone - 1 : $timezone; if (!isset($user->lang['tz_zones'][(string) $timezone])) { $timezone = $config['board_timezone']; } } else { $is_dst = $config['board_dst']; $timezone = $config['board_timezone']; } //用戶所屬組 $coppa=false; $group_name = ($coppa) ? 'REGISTERED_COPPA' : 'REGISTERED'; $sql = 'SELECT group_id FROM ' . GROUPS_TABLE . " WHERE group_name = '" . $db->sql_escape($group_name) . "' AND group_type = " . GROUP_SPECIAL; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); $group_id = $row['group_id']; if (($coppa || $config['require_activation'] == USER_ACTIVATION_SELF || $config['require_activation'] == USER_ACTIVATION_ADMIN) && $config['email_enable']) { $user_actkey = gen_rand_string(10); $key_len = 54 - (strlen($server_url)); $key_len = ($key_len < 6) ? 6 : $key_len; $user_actkey = substr($user_actkey, 0, $key_len); $user_type = USER_INACTIVE; $user_inactive_reason = INACTIVE_REGISTER; $user_inactive_time = time(); } else { $user_type = USER_NORMAL; $user_actkey = ''; $user_inactive_reason = 0; $user_inactive_time = 0; } //如果這個用戶不存在,則自動注冊之,然后再登錄 $user_row = array( 'username' => utf8_normalize_nfc($username), 'user_password' => phpbb_hash($password), 'user_email' => strtolower($useremail), 'group_id' => (int) $group_id, 'user_timezone' => 0, 'user_dst' => $is_dst, 'user_lang' => 'zh_cmn_hans', 'user_type' => $user_type, 'user_actkey' => $user_actkey, 'user_ip' => $user->ip, 'user_regdate' => time(), 'user_inactive_reason' => $user_inactive_reason, 'user_inactive_time' => $user_inactive_time, 'user_dateformat' => 'Y-m-d G:i', ); $user_id = user_add($user_row); if($user_id){ $sql = 'SELECT user_id, username, user_password, user_passchg, user_pass_convert, user_email, user_type, user_login_attempts FROM ' . USERS_TABLE . " WHERE username_clean = '" . $db->sql_escape(utf8_clean_string($username)) . "'"; $result = $db->sql_query($sql); $row = $db->sql_fetchrow($result); $db->sql_freeresult($result); }else{ return array( 'status' => LOGIN_ERROR_USERNAME, 'error_msg' => 'LOGIN_ERROR_USERNAME', 'user_row' => array('user_id' => ANONYMOUS), ); } } $show_captcha = $config['max_login_attempts'] && $row['user_login_attempts'] >= $config['max_login_attempts']; //這一段,好像是密碼登錄錯誤次數(shù)的統(tǒng)一 // If there are too much login attempts, we need to check for an confirm image // Every auth module is able to define what to do by itself... if ($show_captcha) { // Visual Confirmation handling if (!class_exists('phpbb_captcha_factory')) { global $phpbb_root_path, $phpEx; include ($phpbb_root_path . 'includes/captcha/captcha_factory.' . $phpEx); } $captcha =& phpbb_captcha_factory::get_instance($config['captcha_plugin']); $captcha->init(CONFIRM_LOGIN); $vc_response = $captcha->validate($row); if ($vc_response) { return array( 'status' => LOGIN_ERROR_ATTEMPTS, 'error_msg' => 'LOGIN_ERROR_ATTEMPTS', 'user_row' => $row, ); } else { $captcha->reset(); } } //接下來采用oauth2的password模式登錄 //這一段好像是新舊密碼轉(zhuǎn)換功能 // If the password convert flag is set we need to convert it if ($row['user_pass_convert']) { // in phpBB2 passwords were used exactly as they were sent, with addslashes applied $password_old_format = isset($_REQUEST['password']) ? (string) $_REQUEST['password'] : ''; $password_old_format = (!STRIP) ? addslashes($password_old_format) : $password_old_format; $password_new_format = ''; set_var($password_new_format, stripslashes($password_old_format), 'string'); if ($password == $password_new_format) { if (!function_exists('utf8_to_cp1252')) { global $phpbb_root_path, $phpEx; include($phpbb_root_path . 'includes/utf/data/recode_basic.' . $phpEx); } // cp1252 is phpBB2's default encoding, characters outside ASCII range might work when converted into that encoding // plain md5 support left in for conversions from other systems. if ((strlen($row['user_password']) == 34 && (phpbb_check_hash(md5($password_old_format), $row['user_password']) || phpbb_check_hash(md5(utf8_to_cp1252($password_old_format)), $row['user_password']))) || (strlen($row['user_password']) == 32 && (md5($password_old_format) == $row['user_password'] || md5(utf8_to_cp1252($password_old_format)) == $row['user_password']))) { $hash = phpbb_hash($password_new_format); // Update the password in the users table to the new format and remove user_pass_convert flag $sql = 'UPDATE ' . USERS_TABLE . ' SET user_password = \'' . $db->sql_escape($hash) . '\', user_pass_convert = 0 WHERE user_id = ' . $row['user_id']; $db->sql_query($sql); $row['user_pass_convert'] = 0; $row['user_password'] = $hash; } else { // Although we weren't able to convert this password we have to // increase login attempt count to make sure this cannot be exploited $sql = 'UPDATE ' . USERS_TABLE . ' SET user_login_attempts = user_login_attempts + 1 WHERE user_id = ' . $row['user_id']; $db->sql_query($sql); return array( 'status' => LOGIN_ERROR_PASSWORD_CONVERT, 'error_msg' => 'LOGIN_ERROR_PASSWORD_CONVERT', 'user_row' => $row, ); } } } //檢查用戶輸入的密碼是否正確 // Check password ... if (!$row['user_pass_convert'] && phpbb_check_hash($password, $row['user_password'])) { // Check for old password hash... if (strlen($row['user_password']) == 32) { $hash = phpbb_hash($password); // Update the password in the users table to the new format $sql = 'UPDATE ' . USERS_TABLE . " SET user_password = '" . $db->sql_escape($hash) . "', user_pass_convert = 0 WHERE user_id = {$row['user_id']}"; $db->sql_query($sql); $row['user_password'] = $hash; } //當?shù)卿洺晒r,將用戶重試的次數(shù)清零 if ($row['user_login_attempts'] != 0) { // Successful, reset login attempts (the user passed all stages) $sql = 'UPDATE ' . USERS_TABLE . ' SET user_login_attempts = 0 WHERE user_id = ' . $row['user_id']; $db->sql_query($sql); } // 用戶未激活時返回的錯誤消息 if ($row['user_type'] == USER_INACTIVE || $row['user_type'] == USER_IGNORE) { return array( 'status' => LOGIN_ERROR_ACTIVE, 'error_msg' => 'ACTIVE_ERROR', 'user_row' => $row, ); } //用戶登錄成功 // uccessful login... set user_login_attempts to zero... return array( 'status' => LOGIN_SUCCESS, 'error_msg' => false, 'user_row' => $row, ); } // Password incorrect - increase login attempts $sql = 'UPDATE ' . USERS_TABLE . ' SET user_login_attempts = user_login_attempts + 1 WHERE user_id = ' . $row['user_id']; $db->sql_query($sql); // Give status about wrong password... return array( 'status' => ($show_captcha) ? LOGIN_ERROR_ATTEMPTS : LOGIN_ERROR_PASSWORD, 'error_msg' => ($show_captcha) ? 'LOGIN_ERROR_ATTEMPTS' : 'LOGIN_ERROR_PASSWORD', 'user_row' => $row, ); } caijicheOauthClient.php的主要內(nèi)容符下: <?php class CaijicheOAuthClient{ //private $params = array();//參數(shù)數(shù)組 //客戶端的用戶名 public $client_id; //客戶端的密碼 public $client_secret; //返回網(wǎng)址 public $callback_url; private $requestToken; private $requestTokenSecret; private $access_token; private $expires_in = 3600;//access_token的生命周期。 // 服務器描述信息 private $server = array( "server_uri" => "http://www.", 'request_token_uri' => 'http://www./?mod=OAuth&action=requestToken', 'authorize_uri' => 'http://www./?mod=OAuth&action=authorize', 'access_token_uri' => 'http://www./?mod=OAuth&action=accesstoken',//獲取請求令牌 'getuserinfo_uri' => 'http://www./?mod=OAuth&action=getUserInfo',//獲取用戶信息的服務器地址 ); /** * authorize接口 * * @param string $url 授權(quán)后的回調(diào)地址,站外應用需與回調(diào)地址一致,站內(nèi)應用需要填寫canvas page的地址 * @param string $response_type 支持的值包括 code 和token 默認值為code * @param string $state 用于保持請求和回調(diào)的狀態(tài)。在回調(diào)時,會在Query Parameter中回傳該參數(shù) * @return array */ public function getAuthorizeURL( $url=NULL, $response_type = 'code', $state = NULL, $display = NULL ) { $params = array(); $params['client_id'] = $this->client_id; $params['redirect_uri'] = is_null($url)?$this->callbackurl:$url; $params['response_type'] = $response_type; $params['state'] = $state; //log::debug("getAuthorizeURL params".var_export($params,true)); return $this->server['authorize_uri']. "&" . http_build_query($params); } /** * 構(gòu)造函數(shù) * @param array $config */ public function __construct($config) { if(is_array($config)){ if(isset($config['client_id']))$this->client_id = $config['client_id']; if(isset($config['client_secret']))$this->client_secret = $config['client_secret']; if(isset($config['callback_url']))$this->callbackurl = $config['callback_url']; } } /** * 獲取未授權(quán)的令牌 */ public function getRequestToken(){ $data = "oauth_client_key=".$this->key; $result = json_decode($this->do_call($this->server['request_token_uri'],$data)); $this->requestToken = $result->token; $this->requestTokenSecret = $result->token_secret; return $this->requestToken; } /** * 發(fā)送請求用的 * @param unknown_type $url * @param unknown_type $postdata */ private function do_call($url, $postdata=NULL) { //log::debug("do_call url = " . $url); $ch = curl_init(); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($ch, CURLOPT_POST, TRUE); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_POSTFIELDS, $postdata); curl_setopt($ch, CURLOPT_URL, $url); $ret =curl_exec($ch); //var_dump($ret); //log::debug("do_call return:" . var_export($ret,true)); curl_close($ch); return $ret; } /** * access_token接口 * * @param string $type 請求的類型,可以為:code, password, token * @param array $keys 其他參數(shù): * - 當$type為code時: array('code'=>..., 'redirect_uri'=>...) * - 當$type為password時: array('username'=>..., 'password'=>...) * - 當$type為token時: array('refresh_token'=>...) * @return array */ public function getAccessToken( $keys ,$type = 'code' ) { $params = array(); $params['client_id'] = $this->client_id; $params['client_secret'] = $this->client_secret; if($type=='code'){ $params['grant_type'] = 'authorization_code'; $params['code'] = $keys['code']; $params['redirect_uri'] = $keys['redirect_uri']; }else if($type=='password'){ $params['grant_type'] = 'password'; $params['username'] = $keys['username']; $params['password'] = $keys['password']; }else{ //未知的請求類型 return; } $response = $this->do_call($this->server['access_token_uri']."&".http_build_query($params)); $token = json_decode($response, true);//轉(zhuǎn)換成數(shù)組 if ( is_array($token) && !isset($token['error']) ) { $this->access_token = $token['access_token']; $this->expires_in = $token['expires_in']; } else { //throw new OAuthException("get access token failed." . $token['error']); //授權(quán)出錯 } return $token; } /** * * 獲取用戶訪問信息 * @param unknown_type $access * @param unknown_type $openid * @param unknown_type $aid */ public function getUserInfo($access_token){ $data="access_token={$access_token}&format=json"; $user=$this->do_call($this->server['getuserinfo_uri'],$data); $arr=json_decode($user,true); return $arr; } /** * 簽名生成算法 * @param array $params API調(diào)用的請求參數(shù)集合的關聯(lián)數(shù)組,不包含sign參數(shù) * @param string $secret 簽名的密鑰即獲取access token時返回的session secret * @return string 返回參數(shù)簽名值 */ function getSignature($params, $secret) { $str = ''; //待簽名字符串 //先將參數(shù)以其參數(shù)名的字典序升序進行排序 ksort($params); //遍歷排序后的參數(shù)數(shù)組中的每一個key/value對 foreach ($params as $k => $v) { //為key/value對生成一個key=value格式的字符串,并拼接到待簽名字符串后面 $str .= "$k=$v"; } //將簽名密鑰拼接到簽名字符串最后面 $str .= $secret; //通過md5算法為簽名字符串生成一個md5簽名,該簽名就是我們要追加的sign參數(shù)值 return md5($str); } } ?> |
|
來自: 昵稱10854698 > 《待分類1》