2022-07-16

【PHP】LINE 官方帳號 以 Account link 綁定 網站/公司 既有會員

參考資料 ----
LINE Messaging API

有時候,您的公司在成立 LINE 官方帳號前,早就已經建立官網多時,這時我們希望能將 LINE 使用者與網站上的會員綁定,以提供會員更好的服務。
下圖是整個綁定的流程


先在官方帳號後方設定圖文選單,當使用者按下 選項 B 時,會送出 【綁定帳號】 給 LINE 機器人程式,接下來就開始綁定流程


按下選項 B,開始綁定流程


將使用者導至網站登入頁,輸入 帳號、密碼


完成驗證,重導至 LINE 綁定成功頁面







LINE 機器人程式
 
<?php
date_default_timezone_set('Asia/Taipei');
$channelAccessToken = '{blablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablablabla}';
 
$bodyMsg = file_get_contents('php://input');

// 寫 log
$sLogfile = './log/log_'.date('Ymd').'.log';
$fp = fopen($sLogfile, "a+");
fwrite($fp , print_r(date('Y-m-d H:i:s').', Recive: '.$bodyMsg."\n", true));
fclose($fp);


 
$obj = json_decode($bodyMsg, true);
$payload = null;
$event = null;
 
 
foreach ($obj['events'] as &$event)
{
    switch($event['type'])
    {
        // user 傳來訊息
        case 'message':
            $userId = $event['source']['userId'];
            // 取得 使用者傳來的訊息
            $msgUser = $event['message']['text'];
            // 判斷 client 端傳訊型態
            switch($event['message']['type'])
            {
                // 文字
                case 'text':
                {
                    switch($event['message']['text'])
                    {
                        ...
                        ...

                        case '【綁定帳號】':
                            // 1. 向 LINE 平台申請 link token
                            $ch = curl_init();
                            curl_setopt($ch, CURLOPT_URL,"https://api.line.me/v2/bot/user/$userId/linkToken");
                            curl_setopt($ch, CURLOPT_POST, true);
                            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
                            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
                            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
                            curl_setopt($ch, CURLOPT_HTTPHEADER, [  'Content-Type: application/json',
                                                                    'Authorization: Bearer ' . $channelAccessToken
                                                                ]);
                            $result = curl_exec($ch);
                            curl_close($ch);
                            // 寫 log
                            $sLogfile = './log/log_'.date('Ymd').'.log';
                            $fp = fopen($sLogfile, "a+");
                            fwrite($fp , print_r(date('Y-m-d H:i:s').', LINE resule: '.$result."\n", true));
                            fclose($fp);

                            // 2. LINE 平台回覆 linkToken 給 機器人
                            $objResult = json_decode($result, true);
                            $linkToken = $objResult['linkToken'];
                            // 寫 log
                            $sLogfile = './log/log_'.date('Ymd').'.log';
                            $fp = fopen($sLogfile, "a+");
                            fwrite($fp , print_r(date('Y-m-d H:i:s').", decode json → linkToken = $linkToken \n", true));
                            fclose($fp);

                            // 3. 傳送 linking URL 給 LINE 平台
                            $payload = ["to" => $userId,
                                        "messages" => [
                                                        [ 
                                                            "type" => "template",
                                                            "altText" => "Account Link",
                                                            "template" => [
                                                                            "type" => "buttons",
                                                                            "text" => "綁定帳號",
                                                                            "actions" => [
                                                                                                [
                                                                                                    "type" => "uri",
                                                                                                    "label" => "登入",
                                                                                                    "uri" => "https://網址/line/link.php?linkToken=$linkToken"
                                                                                                ]
                                                                                            ]
                                                                        ]
                                                        ]
                                                    ]
                                    ];
                            $ch = curl_init();
                            curl_setopt($ch, CURLOPT_URL,"https://api.line.me/v2/bot/message/push");
                            curl_setopt($ch, CURLOPT_POST, true);
                            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
                            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
                            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
                            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
                            curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
                            curl_setopt($ch, CURLOPT_HTTPHEADER, [  'Content-Type: application/json',
                                                                    'Authorization: Bearer ' . $channelAccessToken
                                                                ]);
                            $result = curl_exec($ch);
                            curl_close($ch);
                            // 寫 log
                            $sLogfile = './log/log_'.date('Ymd').'.log';
                            $fp = fopen($sLogfile, "a+");
                            fwrite($fp , print_r(date('Y-m-d H:i:s').', Redirect user resule: '.$result."\n", true));
                            fwrite($fp , print_r("encode payload = ".json_encode($payload)." \n", true));
                            fclose($fp);

                            // 4. LINE 平台將 user 導至網站登入頁面

                            exit;
                    }
                }
            }
            break;

        case 'accountLink':
            11. LINE 平台傳送 會員的 userId 給機器人
            $userId = $event['source']['userId'];
            $nonce = $event['link']['nonce'];
            
            12. 在資料庫找到 user, 並存入該會員的 LINE userId
            // 寫 log
            $sLogfile = './log/log_'.date('Ymd').'.log';
            $fp = fopen($sLogfile, "a+");
            fwrite($fp , print_r(date('Y-m-d H:i:s').', 藉由 nonce: '.$nonce." 在資料庫中找到使用者, 並存入 userId($userId), 完成綁定 \n", true));
            fclose($fp);
            exit;
    }
}
?>

 




網站登入程式 link.php
 
<?php
    // 在本例, 我們偷懶, 將 step 5 ~ 9 都寫在同一支程式
    // setp 5 在下方

    // 7. 驗證登入
    if(isset($_POST['token']))
    {   // user submit
        // 驗證登入資訊
        // 略, 偽裝 user 通過驗證
        $id = $_POST['id'];
        $pwd = $_POST['pwd'];
        $token = $_POST['token'];

        // 8. 產生 nonce 並存入資料庫, 以便後面流程連結 userId 用
        $nonce = base64_encode(random_bytes(16));

        // 9. 重導至綁定成功頁面
        echo "<script>
                location.href='https://access.line.me/dialog/bot/accountLink?linkToken=$token&nonce=$nonce'
            </script>";
        exit;
    }
?>
<html>
<body>
<?php
    // 5. user 引導至網站登入頁
    if(isset($_GET['linkToken']))
    {
        $linkToken = $_GET['linkToken'];
    }

    // 6. 顯示登入頁面
?>
<center>
    <form id="frmLogin" method="post" action="link.php" style="font-size:30pt;">
        <table border="0">
            <tr>
                <td><input type="hidden" id="hidToken" name="token" value="<?php    echo $linkToken;    ?>" /></td>
            </tr>
            <tr>
                <td><input type="text" id="txtID" name="id" maxlength="20" width="50" /></td>
            </tr>
            <tr>
                <td><input type="password" id="txtPwd" name="pwd" maxlength="20" width="50" /></td>
            </tr>
            <tr>
                <td><input type="submit" text="提交" />  <input type="reset" text="重填" /></td>
            </tr>
        </table>
    </form>
</center>
</body>
</html>
 

解除綁定相對簡單多了,因為 event 都會含 userId,所以藉由 userId 去資料庫找,將該會員的 userId 欄位清除即可。

沒有留言:

張貼留言