2018/1/8

第二十天:串接 Line Messaging API Webhook

markdown 大家還記得為什麼我們要作網站嗎?是因為我們要作 Line 聊天機器人啦。因為作 Line 所提供的 Line Messaging API Webhook 是透過 HTTP 協定來完成,所以我們需要弄一台網頁伺服器,讓 Line 有事情時可以透過 HTTP 協定來通知我們。 我們從[第四天:認識 Webhook](https://ithelp.ithome.com.tw/articles/10193212)開始學習怎麼架網頁伺服器,直到[第十九天:發布網站到 Heroku (續)](https://ithelp.ithome.com.tw/articles/10196250),終於成功作出一個能讓別人連線的網頁伺服器。 當然在這個過程中,我們學會的不只是會架網站。我們還學會了怎麼使用檔案總管、小黑框、Sublime Text、git 和 heroku。這中間並沒有浪費時間,因為所有的學習都會在這個時候用上。而你終於有能力可以開始來接 Line Messaging API 啦。 接下來的文章會採取一邊實作,一邊說明的方式。同時也會一邊複習之前學過的東西。而今天我們的目標是完成 Line Messaging API Webhook 的串接。 # 接收第一個 POST 請求 因為 Line 會傳東西給我們,所以 HTTP 請求方法會是 `POST`,不會是以往我們使用的 `GET`,我們先作一個能接受 `POST` 的網址出來: 在 `config/routes.rb` 加入一行: ``` post '/kamigo/webhook', to: 'kamigo#webhook' ``` 在 `app/controllers/kamigo_controller.rb` 加入以下函數: ``` def webhook head :ok end ``` `head :ok` 的意思是傳回 HTTP status code :`200` 以及空的 HTTP body。複習一下在[第十二天:從瀏覽器認識 HTTP 協定](https://ithelp.ithome.com.tw/articles/10195016)有學過的,HTTP status code :`200` 表示成功。也就是說不管誰,傳什麼內容過來,我都會回一個成功。 用 `rails server` 開啟網頁伺服器,試試看直接在瀏覽器輸入網址 [http://localhost:3000/kamigo/webhook](http://localhost:3000/kamigo/webhook): ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjyKvCT3iJVXTLqGzWH3jQE0Nj8sfB1Esz1cTS3PwjyaWF7984ypgpBcFhIh0ICd91ecM7TUhJ_KOomFT2NZfwG0ey-ewrRwHWPRMlRXc1c64xOplk8cu2WA70GqP5r3zPYJmLXZc28o94/s1600/3.png) Rails 返回的結果是 `No route matches [GET] "/kamigo/webhook"`,意思是我們沒有設定 `GET` 連接到 `/kamigo/webhook`,這表示我們直接在瀏覽器網址列輸入網址的話,是不可能產生出一個 `POST` 請求的。 有幾個方法可以作出 `POST` 請求,最常見的 `POST` 請求是在一個網頁上填表單按下送出的時候。我們不會採用這個方案,因為這個方案要寫程式。我們可以使用現成的工具來發出 POST 請求。 # POST 的測試 有一款工具叫作 POSTMAN:[https://www.getpostman.com/](https://www.getpostman.com/) ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEi3O6Lt1aoqaoYBoCydndkjTI3WFdSFwi2fGqTaEi6AGEy-XOYzH1LmGlFfSXLjukTbXJVEU-vAxSgtrLc2VSdVc0rE2Fj_pPxPQpOBIoxZr4GzXALllrkb0OYznwX0E8Y-KcTAcTskUPg/s1600/4.jpg) 點一下 `Windows`。 ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjEd1t6KT1Y21-6EOVLnHb-8Op-uM9FfppKBdyF3PLAFN9JNhHqYLJzmTYtujOnz-MYF_Vvgg-NJTOWAU9VjSqRgmQCzTiTEwBCLQz7cMeCUwJfhxAhf46jApBuxPZ4XeTy4CpFaAovfHw/s1600/5.jpg) 選 `x64` 就會開始下載,下載好就點開。 ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEilZn1o5kVlbp1Q-kmuTeqDj92ZECT0_krcVYd_BCUDQHFzUarFnuyVd4HMmMOzWUNAN_QLi6DYaaR2VwWX6RMtGKorTpBx0HkuLUUZk9E4I6qqt34WOrmEUXfGI-HHqOimeQgmTjdaLO0/s1600/6.jpg) POSTMAN 是一款功能眾多的軟體,但我們用不到進階功能,所以我們就不註冊帳號了,點選下面圈起來的 `Take me straight to the app. I'll create an account another time.` 略過註冊,直接使用。 ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiYcOIV5sakgZLI2-1DuE-fiF2eZ9-9YRN_dIidlK8BaE2wtOXWODr4M83rJKDvP4wqFNBWRileUFVdbhhlec0UYDftIiclS8ZZrGmfB29HxN4d-0VmaCSPZxMu0SmZ5k7tzSH8UHKQOgw/s1600/7.jpg) 這是我們用不到的各種功能,直接關掉即可。 ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhoo5IEmS55g17gFO1qQtDm6XFHORXd_i0zfc3INCcdU_Z-Kb5iB-D4ZpxcLbhAKYC02kNIX-gPLzN5hXXBb8zPkHR_rfRcOG0r-W9ygehD5illS3-utmGXBjJJ39KmYdmbmPzvqrazo0A/s1600/8.jpg) 這個區塊是讓我們填入 HTTP 請求方法和網址的地方。我們要用 `POST` 方法,網址是 `http://localhost:3000/kamigo/webhook`,填好按送出。 ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhNJ6zBAMuI-3DuD0YG65UJAoD4E6N_TBvWyefzQ6aqs__ymrbgriG51GDZZyDA1PHeOmhST7JbGmshZIpXbaTLbk9VLP2XxDv88BMOilfawLMoYpAF_UvWySKng-TvKxlfkcgltqb1CiU/s1600/9.jpg) 結果收到的 status code 是 `422`,這是怎麼回事呢? 檢查一下 rails server 的小黑框會看到: ``` Started POST "/kamigo/webhook" for 127.0.0.1 at 2018-01-08 01:55:37 +0800 Processing by KamigoController#webhook as */* Can't verify CSRF token authenticity. Completed 422 Unprocessable Entity in 2ms ActionController::InvalidAuthenticityToken (ActionController::InvalidAuthenticityToken): ...下略 ``` 為了防止世界被破壞,為了守護世界的和平...這是為了防範一種叫作 `CSRF` 的入侵手法。大概解釋一下他的原理:我可以作一個網頁,讓你在開啟網頁時,就讓你的瀏覽器對另一個網站發出 `POST` 請求,因為是從你的瀏覽器發出的,所以另一個網站如果沒有作檢查,可能就會中招。`CSRF` 可以代替你做很多事,比方說如果 Line 沒有防的話,我就可以讓你買 Line 貼圖送給我。 # 圖解 CSRF ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhP4dXzikFb3w3rNtldyzAPIzekR3JqoZkjMUqdXX-SR2Aez3Ic86MdlbN92mF0HCo1DRrOm4Sg5_RMPPDJvOIbKeV7A0lIXyaOUdQiYSqiMxpMAYrT6kVtsyQWQl1NxUYP9KhXBaQC6SM/s1600/10.jpg) 這是正常的情況,一個人類應該會先開啟一個表單頁,填好表之後再送出。 ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj5hdTVpKghiiL-YK4yCo1t-Cgcx_B7NFKb7cGGjYjP-d7Ens8GHDFKqilIbuppLlvOv1cFoBDabzxOIjRj4xA8jNI5sPRMNo4TQ37Ta6LDNB_prnTBv317GECPiBlRYeqePqgzZyF-vKQ/s1600/11.jpg) 這是被入侵時會發生的情況,壞網頁會讓你的瀏覽器在不經過你同意的情況下,自己發出 `POST` 請求給另一個網站。 # CSRF 的防治 為了防止這個情形,我們的 Rails 網站會在人類在發出 `GET` 請求開啟表單頁時,就先給你一個號碼牌(`CSRF token`),只有帶著正確號碼的號碼牌的人才能進 `POST` 請求,要不然就會被門口的警衛擋下來。但因為 Line 只會直接對我們發 `POST`,所以我們不能使用表單號碼牌的機制,我們會使用的是 Line 給我們的 `Channel access token`,這部分之後會再說明。 # 關閉 CSRF 的檢查 我們不能透過 Rails 內建的檢查機制來防治 `CSRF`,所以我們得先關閉內建的 `CSRF` 檢查。 在 `app/controllers/kamigo_controller.rb` 中加入一行: ``` protect_from_forgery with: :null_session ``` 通常這行會放在最上面,像這樣: ``` class KamigoController < ApplicationController protect_from_forgery with: :null_session ...下略 ``` 弄好後存檔,此時再去按 POSTMAN 的 `Send`,就會得到 Status: 200 OK,而我們的小黑框顯示的變成這樣: ``` Started POST "/kamigo/webhook" for 127.0.0.1 at 2018-01-08 02:41:37 +0800 Processing by KamigoController#webhook as */* Can't verify CSRF token authenticity. Completed 200 OK in 3ms ``` 其中的 Can't verify CSRF token authenticity. 是在講說他沒有完成 CSRF 檢查。 # 上傳程式碼 我們上傳程式碼,上傳程式碼的三步驟: ``` git add . git commit -m "新增 webhook" git push heroku master ``` 應該是會成功啦,我就不貼訊息了。 # 串接 Line Messaging API Webhook 開啟 Line developer 後台 [https://developers.line.me/console/](https://developers.line.me/console/): ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjR4XX-0afM7EMloUrdMQYnWkLYLSdvpxhlXV-JcVIKH9kIZBj6RA6tp8Ih6g5hWEPlAPmhw0EJcyHFTc9OS7oJxlv02CciBe5rKYCh5Nw1ASNFQN2cU85IbKvJWrHMf0BLJnVa5DcZYgM/s1600/1.jpg) 點聊天機器人進入: ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiysddxxB2o1qh_FCsPIsBUV10xO9lJnlSuxsQ_2i5-tARrmxkmOyDES3PF4vXnYwi6onl9wIcYczXSGvEXsHhU5qR3DI0og8bqEBAVg0jlPyVZTfJ0FkbwvhnEYic1aTg2lGM3BvuCyaQ/s1600/12.jpg) 進入頁面後,你要找到上圖所在的 `Messaging settings` 區塊,其中有一項叫作 `Webhook URL`,點一下右邊的筆進入編輯: ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEggB-6lf6huwfkuQC2xakHwNk5xyhKS9YmVD60NWJ59wg6ZEUtp_ijAsiYlJITtII4aqJjyDBSTHUE66AyNMEMXzdPmCOjU4CEoChXNlNasEGw37LCs2TetA38f-DFG_dayuD7vzw_ym7Q/s1600/13.jpg) 輸入我們剛剛作好的 POST 網址 `people-all-love-kamigo.herokuapp.com/kamigo/webhook`,注意這裡你要填的是你的網站的網址,不要填到我的。還有一個注意事項,開頭的 `https://` 不可以填。 填好後按下 `Update`。 ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhX5f7qOlwnuoxt0MHt1jeUtU-invHKJdgVbxQ36JK99tf0CopAMAZHVvjojkiNcV_DWRMDk4m90MQJPZtTtIQm5FLHZnooaeIq8cHPwyUVee0Ho5lX_44o9YogXSZCdMD7auPf-DbTApo/s1600/14.jpg) 就會在畫面上看到一個 `Verify` 按紐,按下去。 ![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiq6UuZPKpPjFTYC9iWb_6nJFcifRkHSw-9mEmfTYXh4ecp6R-KJvANw8jjdc1VTVKeBQGCQK11Yay7jkUR-9J6WdLHD9X4k3pfu_Z7qmNIyTFeE-a2P0MYAU5LsSqPcsKwTzhgQFDFu7Y/s1600/15.jpg) Success 成功! 今天就先到這,明天就能讓聊天機器人講話了。

沒有留言: