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://3.bp.blogspot.com/-HE81gj5GpU4/WlJWtQd8ddI/AAAAAAABAU8/0QeEIysNoPEZlI9CDBdGyK2_vZ8lcSuVQCLcBGAs/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://4.bp.blogspot.com/-ml_UCEZxFyg/WlJYTRhcbPI/AAAAAAABAVI/VmoYaZut18QYjY2yXqZcnd9DahO0AzHUwCLcBGAs/s1600/4.jpg) 點一下 `Windows`。 ![](https://4.bp.blogspot.com/-Ip5F6IcAiNw/WlJbDog_pcI/AAAAAAABAVU/ytE3199XaBY8C-nUCxlADE004CQJPJaaACLcBGAs/s1600/5.jpg) 選 `x64` 就會開始下載,下載好就點開。 ![](https://2.bp.blogspot.com/-Rhc3JxcWRw4/WlJbttYNIsI/AAAAAAABAVc/38RH-10XIcsI0YTyeDEzHJbLRpWXH_-NgCLcBGAs/s1600/6.jpg) POSTMAN 是一款功能眾多的軟體,但我們用不到進階功能,所以我們就不註冊帳號了,點選下面圈起來的 `Take me straight to the app. I'll create an account another time.` 略過註冊,直接使用。 ![](https://2.bp.blogspot.com/-iiuKZB9eDi8/WlJcR5qxaJI/AAAAAAABAVk/vwTlbscRilMPwXj5dnpLHsE-s4z1_OvRgCLcBGAs/s1600/7.jpg) 這是我們用不到的各種功能,直接關掉即可。 ![](https://1.bp.blogspot.com/-l8ZRJ7HXq20/WlJcnWJ54JI/AAAAAAABAVo/LcwNFrkx9Qk7nG_y9fCaSJfMeJXrBksZACLcBGAs/s1600/8.jpg) 這個區塊是讓我們填入 HTTP 請求方法和網址的地方。我們要用 `POST` 方法,網址是 `http://localhost:3000/kamigo/webhook`,填好按送出。 ![](https://3.bp.blogspot.com/-DnGyV9Cqfxo/WlJeobnSXaI/AAAAAAABAWA/DAIZ_Mid-q44b9I-TBOjkKH_vgL0EPP9wCLcBGAs/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://1.bp.blogspot.com/-JIcr02_qL1w/WlJlfp_EHBI/AAAAAAABAWU/QGnRrgDhbrENev6NL3lMazOn791oQH0mACLcBGAs/s1600/10.jpg) 這是正常的情況,一個人類應該會先開啟一個表單頁,填好表之後再送出。 ![](https://4.bp.blogspot.com/-0WvD_rM6Ij4/WlJl-udyQLI/AAAAAAABAWY/h7GphTJFQHUMQBUrtK-DcRuum_tQqkcmgCLcBGAs/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://1.bp.blogspot.com/-fHUoOw-KRmI/WlJsB-rNAlI/AAAAAAABAWo/86oSeqrfZechYVZ6lGGt_t-J4I7qnut9wCLcBGAs/s1600/1.jpg) 點聊天機器人進入: ![](https://4.bp.blogspot.com/-N4stOwWBvn8/WlJs44yTujI/AAAAAAABAWw/Ppu72SGyv-4yFFtVyb5DesLVQ6Q8XRZRgCLcBGAs/s1600/12.jpg) 進入頁面後,你要找到上圖所在的 `Messaging settings` 區塊,其中有一項叫作 `Webhook URL`,點一下右邊的筆進入編輯: ![](https://1.bp.blogspot.com/-lp5WrG2nZ6I/WlJtZb8paWI/AAAAAAABAW8/BYzAwly8nNspM4x9HtJTvK3K9N88nMv7gCLcBGAs/s1600/13.jpg) 輸入我們剛剛作好的 POST 網址 `people-all-love-kamigo.herokuapp.com/kamigo/webhook`,注意這裡你要填的是你的網站的網址,不要填到我的。還有一個注意事項,開頭的 `https://` 不可以填。 填好後按下 `Update`。 ![](https://1.bp.blogspot.com/-cgIhQotg6dQ/WlJuBwFyXYI/AAAAAAABAXE/8aQQXZcDzvo0shgBzdSt_TihXI3aUJovQCLcBGAs/s1600/14.jpg) 就會在畫面上看到一個 `Verify` 按紐,按下去。 ![](https://2.bp.blogspot.com/-RVy7uTxdZ-A/WlJuU6OAV5I/AAAAAAABAXI/-67oog5NyRsm7wyoFAKgxfaJLp-5gX_-QCLcBGAs/s1600/15.jpg) Success 成功! 今天就先到這,明天就能讓聊天機器人講話了。

沒有留言: