本篇文章更新時間:2021/04/14
如有資訊過時或語誤之處,歡迎使用 Contact 功能通知。
一介資男的 LINE 社群開站囉!歡迎入群聊聊~
如果本站內容對你有幫助,歡迎使用 BFX Pay 加密貨幣 或 新台幣 贊助支持。
WordPress 的用途可以很廣,作為個人用或組織用都有一些情境可以套,其中如果本來組織就有自己一套會員系統的話,那登入功能也可以改取代使用原本的會員系統做驗證。
這篇筆記應用的情境正是 WordPress 購物網站與手機 App 的架構整合。
由於手機 App 已經有使用一套雲端的會員系統,又因為希望可以增加購物功能而選用 WordPres + WooCommerce 當作購物車組合。
此情境會碰到一個問題是:手機 App 上已經註冊的用戶,如果拿帳號密碼登入網站要購物,會有 WordPress 這邊本地的會員系統認證問題。
為了要能整合網站與手機 App 的使用者,所以要把登入的機制做一些調整,如下:
以 App 雲端會員登入系統來整合 WooCommerce 購物車
function mxp_custom_authenticate($user, $username, $password) {
// 內建 Email 登入方法如果判斷正確也給登入
$wp_user = get_user_by('email', $username);
$wp_user = apply_filters('wp_authenticate_user', $wp_user, $password);
if (!is_wp_error($wp_user) && wp_check_password($password, $wp_user->user_pass, $wp_user->ID)) {
return $wp_user;
}
// 內建 帳號 登入方法如果判斷正確也給登入
$wp_user = get_user_by('login', $username);
$wp_user = apply_filters('wp_authenticate_user', $wp_user, $password);
if (!is_wp_error($wp_user) && wp_check_password($password, $wp_user->user_pass, $wp_user->ID)) {
return $wp_user;
}
// 都不是,就來呼叫 外部會員驗證 API 的登入方法
$resp = mxp_api_login($username, $password);
$auth_token = '';
if (!empty($resp['data']) && $resp['status'] == 200) {
$auth_token = $resp['data']['auth-token'];
}
// 判斷外部會員登入驗證是否正確
if ($auth_token != "") {
// 取回外部會員資料物件
$user_obj = mxp_get_user_obj($auth_token, 'sel');
$email = $user_obj['data']['email'];
$account = $user_obj['data']['account'];
// 檢查 WordPress 使用者資料庫,判斷是否過去就有註冊過了
$check_wp = email_exists($email);
if ($check_wp) {
// 有註冊過就回傳會員資料,完成登入
$user = new WP_User($check_wp);
return $user;
} else {
// 沒有註冊過就給他註冊與登入同步進行
$username = '';
if ($account != '') {
$check_username = username_exists($account);
if ($check_username === false) {
$username = $account;
} else {
// 帳號重複的話補上一些後綴避開
$username = $account . '_' . time();
}
} else {
// 沒有帳號,就先拿信箱前綴來當帳號
$username = current(explode('@', $email)) . "_" . time();
}
// 註冊一個帳號
$wp_uid = wp_create_user($username, $password, $email);
if (!is_wp_error($wp_uid)) {
// 沒錯誤的話,就給他賦予「顧客」角色,並且通知管理員
$user_id_role = new WP_User($wp_uid);
$user_id_role->set_role('customer');
wp_new_user_notification($wp_uid, null, 'admin');
return $user_id_role;
}
}
}
// 如果上述操作都沒有成功,就留給後面內建的判斷去反應錯誤
return $user;
}
// 執行權重也是設定關鍵,要早於內建的 20 來提早觸發判斷
add_filter('authenticate', 'mxp_custom_authenticate', 10, 3);
如此寫法就能「兼容」WordPress 內建的使用者資料庫與雲端統一登入的會員資料庫。
但... 如果完全不需要 WordPress 內建的使用者資料庫的話?
這樣「單一登入」的情境可以使用下列方法:
function mxp_custom_authenticate($user, $username, $password) {
$whitelist = array(
'mxp',
'管理員帳號',
'mxp.tw',
'或信箱後綴網域',
);
$sub = explode('@', $username);
$allow_domain = end($sub);
$matches = preg_grep('/.*' . $allow_domain . '.*/i', $whitelist);
// 根據白名單判斷是否要走內建登入方式,通常就是網站的管理員帳號
if (!empty($matches)) {
// 如果是指定使用者,不通過 API 來登入
remove_action('authenticate', 'wp_authenticate_username_password', 20, 3);
remove_action('authenticate', 'wp_authenticate_email_password', 20, 3);
}
// 不論是否移除了內建的登入驗證方式,這邊填入上述 API 登入驗證方法,有成功就回傳一個或對應權限的使用者帳號
// .... 省略 code ....
return $user;
}
add_filter('authenticate', 'mxp_custom_authenticate', 10, 3);
如果不做一個白名單機制繞過雲端會員資料庫的話,就是要規劃雲端會員資料庫部分有對應 WordPress 內容管理權限來設計,完成登入驗證部分純外接。
至於註冊部分的取代就又更容易些,很多表單都有提供這樣「註冊表單」的功能,前端欄位確定後,看後端要怎串接雲端資料庫做同步或是純雲端會員新增都可以,也是很吃情境的設計!(通常不會走內建的,欄位不符合後續運用需求)
其他跟帳號連動的操作還有:
- 更新帳號資訊: 主要是
profile_update
這個action
(有要同步內建使用者管理的話) - 忘記密碼:
after_password_reset
的action
,是使用內建找回密碼功能後觸發的事件,如有客製化這塊可以參考。
後記
這樣的驗證機制調整範圍是全站,也就是不管有沒有使用到 WooCommerce 購物車外掛,這樣的方法都通用。
比較正規一點的內網系統可能會使用 LDAP Authentication (LDAP 身份驗證) ,這類型需求也有 WordPress 外掛可以參考 Active Directory Integration / LDAP Integration
不管哪種驗證方式,最重要的還是帳號密碼切勿太簡單,不然一下就被攻破,導致網站出現資安問題,這就跟什麼驗證方式都無關了。
參考資料:
- 5 WordPress Hacks We Used to Build Authentication
- Build a Custom WordPress User Flow — Part 1: Replace the Login Page
- Code Reference authenticate
- Code Reference wp_create_user