WooCommerce API Keys的生成和保存機制

引言

我在一個WordPress項目中使用了WooCommerce插件,該插件提供了REST API的功能,要使用該功能一個很重要的部分就是授權機制。其中官方文章中關於關於HTTPS的授權說明如下:

Over HTTPS
You may use HTTP Basic Auth by providing the API Consumer Key as the username and the API Consumer Secret as the password.

因此,我就按照WooCommerce官方Step-by-Step文章創建了Consumer Key和Consumer Secret,然後通過REST API也完成了數據的獲取、創建、修改等等。

但是,一個要非常注意的地方就是:WooCommerce生成的Key和Secret是無法再次獲取到的,如下圖紅圈中的內容:
Key 詳情

什麼意思呢?就是說你要把Consumer Key和Consumer Secret自己記錄下來,什麼時候你需要的時候自己填入進去,我是不會再提供接口讓你獲取它們了!!!

WTK!現在我既要記住我在WordPress上的登陸賬號密碼,還要在記住WooCommerce的REST API的Key和Secret。
那麼如何通過登錄賬號密碼授權或者在已經登陸授權的情況下獲取到該用戶的Key和Secret。
要實現上面的功能需求,那麼首要的步驟就是了解WooCommerce是如何產生和保存REST API的Key和Secret的。下面我們就從頁面開始入手一層層的深入進去。

頁面流程

class-wc-settings-api.php頁面

WooCommerce插件的REST API設置界面包括以下三個子部分:
代碼文件:woocommerce\includes\admin\settings\class-wc-settings-api.php

    /**
     * Output the settings
     */
    public function output() {
        global $current_section;

        if ( 'webhooks' == $current_section ) {
            WC_Admin_Webhooks::page_output();
        } else if ( 'keys' == $current_section ) {
            WC_Admin_API_Keys::page_output();
        } else {
            $settings = $this->get_settings( $current_section );
            WC_Admin_Settings::output_fields( $settings );
        }
    }
  1. Settings: 對應woocommerce\includes\admin\class-wc-admin-settings.php文件
  2. API_Keys: 對應woocommerce\includes\admin\class-wc-admin-api-keys.php文件
  3. Webhooks: 對應woocommerce\includes\admin\class-wc-admin-webhooks.php文件

class-wc-admin-api-keys.php頁面

在這篇文章中我們主要關注API_Keys部分,也就是class-wc-admin-api-keys.php文件
WC_Admin_API_Keys::page_output()函數的具體實現如下:

    public static function page_output() {
        // Hide the save button
        $GLOBALS['hide_save_button'] = true;

        if ( isset( $_GET['create-key'] ) || isset( $_GET['edit-key'] ) ) {
            error_log('create-key or edit-key');
            $key_id   = isset( $_GET['edit-key'] ) ? absint( $_GET['edit-key'] ) : 0;
            $key_data = self::get_key_data( $key_id );

            include( 'settings/views/html-keys-edit.php' );
        } else {
            error_log('table_list_output');
            self::table_list_output();
        }
    }

從上的代碼來看,創建/修改是走一個流程,顯示所有的Keys列表時另外一個流程。而對於創建和修改的區分是通過參數中edit-key是否爲空來判斷。

html-keys-edit.php頁面

該頁面主要分爲兩個大塊:id爲key-fields的div和id爲tmpl-api-keys-template的script(type爲text/template),其中div部分是設置和生成的時候會用到,而script部分是使用模板來顯示生成後的Key、Secret以及二維碼。

id爲key-fields的div部分包括:

  • 標題
  • 隱藏的key_id字段
  • 具體的key選項字段表格
  • 生成/保存按鈕

而key選項字段表格中包括以下幾個子項:描述、用戶和權限,如果是修改key的頁面,還有Consumer Key 末幾位以及最後使用時間字段。
這些關於UI的部分,代碼不算複雜,此處不再展開。我們重點關注點擊生成按鈕時的處理。

        if ( 0 == $key_id ) {
            submit_button( __( 'Generate API Key', 'woocommerce' ), 'primary', 'update_api_key' );
        }

處理邏輯

創建Key和Secret的具體處理邏輯在woocommerce\includes\class-wc-ajax.php文件的update_api_key()函數,該函數主要包括以下幾個部分:

  1. 初始化
  2. 運行環境檢查
  3. 輸入參數檢查
  4. 如果key_id不爲空,則是更新key信息的處理
  5. 如果key_id爲空,則是創建key信息的處理

在這裏我們重點關注如何創建Key和保存到數據庫的部分。

            if ( 0 < $key_id ) {
                // update api key
            } else {
                $status          = 2;
                $consumer_key    = 'ck_' . wc_rand_hash();
                $consumer_secret = 'cs_' . wc_rand_hash();

                $data = array(
                    'user_id'         => $user_id,
                    'description'     => $description,
                    'permissions'     => $permissions,
                    'consumer_key'    => wc_api_hash( $consumer_key ),
                    'consumer_secret' => $consumer_secret,
                    'truncated_key'   => substr( $consumer_key, -7 )
                );

                $wpdb->insert(
                    $wpdb->prefix . 'woocommerce_api_keys',
                    $data,
                    array(
                        '%d',
                        '%s',
                        '%s',
                        '%s',
                        '%s',
                        '%s'
                    )
                );

                $key_id                  = $wpdb->insert_id;
                $data['consumer_key']    = $consumer_key;
                $data['consumer_secret'] = $consumer_secret;
                $data['message']         = __( 'API Key generated successfully. Make sure to copy your new API keys now. You won\'t be able to see it again!', 'woocommerce' );
                $data['revoke_url']      = '<a style="color: #a00; text-decoration: none;" href="' . esc_url( wp_nonce_url( add_query_arg( array( 'revoke-key' => $key_id ), admin_url( 'admin.php?page=wc-settings&tab=api&section=keys' ) ), 'revoke' ) ). '">' . __( 'Revoke Key', 'woocommerce' ) . '</a>';
            }

通過上面的代碼,我們瞭解到:
1. consumer_key和consumer_secret是通過wc_rand_hash()函數生成一個隨機數再加上固定前綴構成的
2. 存儲到數據庫中的consumer_key是經過wc_api_hash()函數進行加密的內容,而consumer_secret則是直接進行存儲
3. 在數據庫中添加了一個truncated_key字段,用來保存consumer_key的末尾7位

wp_woocommerce_api_keys數據表的結構如下:

Field Type Null Key Default Extra
key_id bigint(20) NO PRI NULL auto_increment
user_id bigint(20) NO NULL
description longtext YES NULL
permissions varchar(10) NO NULL
consumer_key char(64) NO MUL NULL
consumer_secret char(43) NO MUL NULL
nonces longtext YES NULL
truncated_key char(7 ) NO NULL
last_access datetime YES NULL

通過代碼和表結構的對比,我們發現在創建Key後寫入了6個字段的值,而key_id會自動增長後賦值,nonces字段並沒有使用到,而last_access字段是用來保存最後一次訪問的時間。

總結

分析到這裏,我們瞭解了一個WooCommerce API Keys是如何生成並保存到數據庫中的。在下一篇文章中,我們接着分析WooCommerce API接口是如何驗證授權信息的。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章