然而,phpBB3 這邊的規劃:凡事透過 OAuth 登入者,完成登入後還要綁定到 PHPBB3 內部帳號才可以。看得出來可能的影響問題,包含資安等等的。而比較重要的一點是 PHPBB3 帳號底層用 Email 帳號當作獨一無二的 key。
因此,如果想要自動建立帳號,需確保 Email 是獨一無二的資料,這邊就簡單的做個小動作:
1.當使用者完成 OAuth 認證後,使用該服務資訊做出一個 unique email address,例如是 facebook.com 登入的,就拿 fb graph id 再加 graph.facebook.com 拼湊一個 email address:uid@graph.facebook.com 而非拿使用者的資料。
2.建立帳號還需要 username 資訊、phpBB3 group id
3.進行 oauth 帳號與 phpBB3 綁定 (link_account_perform_link)
主體上需改變:phpbb/auth/provider/oauth/oauth.php ,我這邊再埋個小東西,當 oauth provider 有提供 get_user_info 時,才進行自動綁定。
對 phpbb/auth/provider/oauth/oauth.php 的操作:
在 public function login($username, $password) 添加東西即可:
if ($this->request->is_set('code', \phpbb\request\request_interface::GET))
{
$this->service_providers[$service_name]->set_external_service_provider($service);
$unique_id = $this->service_providers[$service_name]->perform_auth_login();
// Check to see if this provider is already assosciated with an account
$data = array(
'provider' => $service_name_original,
'oauth_provider_id' => $unique_id
);
$sql = 'SELECT user_id FROM ' . $this->auth_provider_oauth_token_account_assoc . '
WHERE ' . $this->db->sql_build_array('SELECT', $data);
$result = $this->db->sql_query($sql);
$row = $this->db->sql_fetchrow($result);
$this->db->sql_freeresult($result);
// 添加自動建立帳號流程 -- begin
if (!$row && method_exists($this->service_providers[$service_name], 'get_user_info') && ($user_info = $this->service_providers[$service_name]->get_user_info()))
{
$new_user_data = $this->user_row($user_info['username'], $user_info['user_email']);
// create user automatic
if (!function_exists('user_add'))
{
include($phpbb_root_path . 'includes/functions_user.' . $phpEx);
}
$user_id = user_add($new_user_data);
$data = array(
'user_id' => $user_id,
'provider' => $service_name_original,
'oauth_provider_id' => $unique_id,
);
$this->link_account_perform_link($data);
// Update token storage to store the user_id
$storage->set_user_id($user_id);
$sql = 'SELECT user_id, username, user_password, user_passchg, user_email, user_type, user_login_attempts
FROM ' . $this->users_table . '
WHERE user_id = ' . (int) $user_id;
$result = $this->db->sql_query($sql);
$row = $this->db->sql_fetchrow($result);
$this->db->sql_freeresult($result);
if (!$row)
{
throw new \Exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_ENTRY');
}
// The user is now authenticated and can be logged in
return array(
'status' => LOGIN_SUCCESS,
'error_msg' => false,
'user_row' => $row,
);
}
// 添加自動建立帳號流程 -- end
...
新增一個函數 user_row ,此參考 phpbb/auth/provider/apache.php - private function user_row($username, $password):
private function user_row($username, $user_email)
{
// first retrieve default group id
$sql = 'SELECT group_id
FROM ' . GROUPS_TABLE . "
WHERE group_name = '" . $this->db->sql_escape('REGISTERED') . "'
AND group_type = " . GROUP_SPECIAL;
$result = $this->db->sql_query($sql);
$row = $this->db->sql_fetchrow($result);
$this->db->sql_freeresult($result);
if (!$row)
{
trigger_error('NO_GROUP');
}
// generate user account data
return array(
'username' => $username,
'user_password' => $user_email,
'user_email' => $user_email,
'group_id' => (int) $row['group_id'],
'user_type' => USER_NORMAL,
'user_ip' => $this->user->ip,
'user_new' => ($this->config['new_member_post_limit']) ? 1 : 0,
);
}
如此一來,當使用者透過 oauth 登入時,第一時間若發現沒有系統對應帳號時,會自動建立一組帳號跟 oauth 帳號綁定,而下次再登入時就會因為已經有帳號綁定而登入動作。而 oauth provider 需要添加一個 get_user_info 的函數,以 facebook 來看就是修改 phpbb/auth/provider/oauth/service/facebook.php 檔案:
public function get_user_info()
{
if (!($this->service_provider instanceof \OAuth\OAuth2\Service\Facebook))
{
throw new exception('AUTH_PROVIDER_OAUTH_ERROR_INVALID_SERVICE_TYPE');
}
// This was a callback request, get the token
$this->service_provider->requestAccessToken($this->request->variable('code', ''));
// Send a request with it
$result = json_decode($this->service_provider->request('/me'), true);
if (isset($result['id']) && isset($result['name']))
return array( 'username' => $result['name'] , 'user_email' => $result['id'].'@graph.facebook.com' );
// Return the unique identifier
return NULL;
}