[WordPress] 取代內建登入驗證的單一登入程式開發方法

本篇文章更新時間: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 內容管理權限來設計,完成登入驗證部分純外接。

至於註冊部分的取代就又更容易些,很多表單都有提供這樣「註冊表單」的功能,前端欄位確定後,看後端要怎串接雲端資料庫做同步或是純雲端會員新增都可以,也是很吃情境的設計!(通常不會走內建的,欄位不符合後續運用需求)

其他跟帳號連動的操作還有:

  1. 更新帳號資訊: 主要是 profile_update 這個 action (有要同步內建使用者管理的話)
  2. 忘記密碼: after_password_resetaction,是使用內建找回密碼功能後觸發的事件,如有客製化這塊可以參考。

後記

這樣的驗證機制調整範圍是全站,也就是不管有沒有使用到 WooCommerce 購物車外掛,這樣的方法都通用。

比較正規一點的內網系統可能會使用 LDAP Authentication (LDAP 身份驗證) ,這類型需求也有 WordPress 外掛可以參考 Active Directory Integration / LDAP Integration

不管哪種驗證方式,最重要的還是帳號密碼切勿太簡單,不然一下就被攻破,導致網站出現資安問題,這就跟什麼驗證方式都無關了。

參考資料:

  1. 5 WordPress Hacks We Used to Build Authentication
  2. Build a Custom WordPress User Flow — Part 1: Replace the Login Page
  3. Code Reference authenticate
  4. Code Reference wp_create_user

Share:

作者: Chun

資訊愛好人士。主張「人人都該為了偷懶而進步」。期許自己成為斜槓到變進度條 100% 的年輕人。[///////////____36%_________]

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *


文章
Filter
Apply Filters
Mastodon