﻿# 上手 LINE Notify 不求人：一行代碼都不用寫的推播通知方法

有在經營 [LINE@](https://tw.linebiz.com/) 的商家都知道，其實發送主動推播的成本挺高的。但各位可能不知道的是，LINE 其實也有提供一個 **完全免費** 的訊息推播服務叫做 [LINE Notify](https://notify-bot.line.me/)。由於 LINE Notify 必須走 OAuth 2.0 協定來登入，又需要架設網站作為 Callback URL 用途，如果只是單純想體驗 LINE Notify 的開發者來說，就顯得有點麻煩，畢竟不是每個人都了解 OAuth 2.0 的登入流程。這篇文章我要將 OAuth 2.0 登入流程完全拆解，一步一步的給大家看，並示範如何僅透過 [curl](https://curl.haxx.se/) 與 [ngrok](https://ngrok.com/) 兩套工具軟體，就能走完整個流程，而且一行程式都不用寫！👍

### 運作方式

LINE Notify 是一個「訊息推播」服務，但跟一般開發者所理解的推播不太一樣，他的運作方式是這樣的：

1.  LINE 官方有一個特殊的 **LINE Notify** 帳號 (`@linenotify`)，這是一個 LINEBot 機器人，他是一個專門用來發送訊息的帳號。
    
    你不需要事先加入這個帳號，只要你有訂閱任何一個 LINE Notify 通知服務，他就會主動發訊息給你。
    
2.  任何 LINE 用戶都可以成為 **服務提供者**，可以發送推播給任何人，而且真的完全不用任何費用！
    
    他不像 [LINE@](https://tw.linebiz.com/) 有複雜的驗證程序。
    
3.  任何 LINE 用戶都可以註冊 **一個以上** 的 **服務提供者**，每個 **服務提供者** 通常代表著**某種目的**的通知服務。
    
    例如**某網站斷線**的通知，就可以註冊成一個**服務提供者**。或是某網站有客戶**發出客服要求**，也可以註冊成另一個**服務提供者**。通通免費！
    
4.  所有的 **服務提供者** 都必須由 LINE 用戶 **主動訂閱通知**，該用戶才能收到推播通知，而且**用戶隨時可以[取消通知](https://notify-bot.line.me/my/)**。
    
    一律由官方的 **LINE Notify** 帳號發出訊息，而不是由 LINE@ 官方帳號發出訊息。
    

如果跟付費的 [LINE@](https://tw.linebiz.com/) 通知比起來，我覺得這個 [LINE Notify](https://notify-bot.line.me/) 唯二的缺點就是：

1.  [LINE Notify](https://notify-bot.line.me/) 不像 [LINE@](https://tw.linebiz.com/) 有強烈的**品牌連結**！
2.  所有 LINE 用戶都要**主動訂閱服務**才收的到訊息，而且大部分 LINE 用戶都不清楚 LINE Notify 是什麼東西！

即便如此，用來作為公司內部特定訊息的通知，或是用來整合現有服務的錯誤通知，都是非常經濟又實惠的解決方法，既不用花錢，又可以得到即時推播通知的好處！

### 角色定義

想要嘗試用 LINE Notify 完成通知任務，必須理解以下角色：

1.  服務提供者 (發送訊息方)
    
    通常是一支程式或網站，他必須要有一個可以接受 OAuth 2.0 認證通過後的 `callback` 網址，你必須透過這個網址來獲取未來發送 LINE Notify 通知用的 Access Token (`access_token`)。
    
2.  授權通知方 (任意 LINE 用戶)
    
    只有實際的 LINE 用戶才能授權 LINE Notify 發出通知，你必須擁有一個可以登入 LINE ID 的 E-mail 帳號才能進行授權。
    
3.  訊息接收者 (接受訊息方)
    
    LINE Notify 服務有兩種訊息接收者：
    
    1.  用戶 (`USER`)：其實就是你自己！(授權的這個用戶)
    2.  群組 (`GROUP`)：該用戶曾經加入過的任何一個 LINE 群組。

### 服務提供者 (發送訊息方) 要做的事

1.  透過 ngrok 建立一個外部可存取的網站
    
    安裝 [ngrok](https://ngrok.com/) 工具 (使用 [Chocolatey](https://chocolatey.org/install) 套件管理器)
    
    ```bash
    choco install ngrok
    ```
    
    開啟命令提示字元 (`cmd.exe`) 並執行以下命令：
    
    ```bash
    ngrok http 8888
    ```
    
    > 請注意：你不需要撰寫任何程式碼，也不用真的有 Port 8888 的網站服務！
    
    此時你應該會看到如下畫面，請複製 Forwarding 欄位的一個 `https://xxxxxxxx.ngrok.io` 的網址，這也將會成為你在 LINE Notify 訂閱通知時的 `callback` 參數：
    
    ![2020-02-18\_02-13-30](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/0081b61bb9235bfb3136-74677810-53526400-51f4-11ea-99ae-dc35c515f3d9.png)
    
    開啟瀏覽器並連至 `http://127.0.0.1:4040` 網址，進入 ngrok 的 Web 管理介面，這裡將會紀錄所有連接到 `https://xxxxxxxx.ngrok.io` 網址的 HTTP 封包！
    
2.  進入 [LINE Notify](https://notify-bot.line.me/) 網站並登入 LINE 帳號
    
    如果你第一次使用 LINE App，只需要手機號碼就可以開始使用。但如果要登入 LINE Notify 的話，一定要將帳號綁定「電話號碼」與「電子郵件」才可以使用此服務。
    
    你只要到 LINE App 的設定頁面 (路徑：LINE > 主頁 > 設定 > 我的帳號)，點擊「電子郵件帳號」並設定你常用的 E-mail 即可完成綁定。
    
3.  進入 [管理登錄服務](https://notify-bot.line.me/my/services/) 頁面
    
4.  點擊 [登錄服務](https://notify-bot.line.me/my/services/new) 頁面
    
5.  輸入登錄服務所需的每個欄位
    
    除了 **服務圖片** 欄位外，其餘欄位皆為**必填**欄位。
    
    請設定好懂好記的 **服務名稱**，方便未來發通知的時候，讓使用者知道是誰發送的通知。因為 LINE Notify 通知服務其實是一個 LINEBot 帳號，使用者訂閱的所有通知，全部都是透過這個帳號發送訊息，使用者要從訊息中得知「服務提供者」的唯一方法，就是透過 **服務名稱** 識別。
    
    請務必輸入正確的 **電子郵件帳號**，因為下個步驟將會請你去收信完成電子郵件地址驗證。
    
    而 **Callback URL** 欄位則請輸入你在執行 `ngrok http 8888` 命令時，產生的那個 `https://xxxxxxxx.ngrok.io` 網址 (請**不要**加上斜線結尾)！
    
6.  驗證**電子郵件帳號**是否有效
    
    完成電子郵件帳號驗證後，LINE Notify 服務就算設定完成！
    
7.  取得登錄服務的 `Client ID` 與 `Client Secret` 資訊
    
    請回到 [管理登錄服務](https://notify-bot.line.me/my/services/) 頁面，點擊你剛剛建立的那個登錄服務，即可看見這兩個資訊。
    
    ![2020-02-18\_04-00-14](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/489dafd7ba21c5b9065e-74684198-3e7ecc00-5206-11ea-9283-9642f7c57358.png)
    

### 授權通知方 (任意 LINE 用戶) 要做的事

1.  登入 LINE Notify 訂閱通知介面
    
    使用者必須進入以下網址，才能訂閱**你的 LINE Notify 通知** (特定**服務提供者**提供的通知)：
    
    ```
    https://notify-bot.line.me/oauth/authorize?response_type=code&scope=notify&response_mode=form_post&client_id=xxxxxxxxxxxxxxxxxxxx&redirect_uri=http://xxxxxxxx.ngrok.io/&state=f094a459-1d16-42d6-a709-c2b61ec53d60
    ```
    
    這其實是一個 OAuth 2.0 的登入流程，使用者不太需要真的懂這些，只要能連到這個網址即可訂閱通知。
    
    開發者只要能產生正確的 URL 給使用者用即可，但這個網址又臭又長，每個**查詢字串**的用途說明如下：
    
    -   `scope`: 固定寫 `notify` 就對了。
        
    -   `response_type`: 固定寫 `code` 就對了。
        
    -   `response_mode`: 這個參數可以忽略，但你也可以寫 `form_post` 當成 HTTP 回應的模式。
        
    -   `redirect_uri`: 請設定你 [ngrok](https://ngrok.com/) 產生的暫時網址，當訂閱完成後，使用者會被導向到這個網址。
        
        > 請特別要注意的一件事，這裡設定的 URL 必須跟你之前註冊時所設定的 **Callback URL** 完全一樣，連網址最後是否有斜線結尾，都要完全一樣才行。
        
    -   `client_id`: 請設定登錄服務的 `Client ID`
        
    -   `state`: 設定一組亂碼，其實輸入什麼都可以，此參數主要用來防止 [CSRF](https://en.wikipedia.org/wiki/Cross-site_request_forgery) 攻擊。
        
2.  選擇您要接收通知的聊天室 (**聊天室**就是**LINE 群組**的意思)
    
    如果使用者想要將通知發給**自己**，可以選擇【**透過1對1聊天接收LINE Notify的通知**】。
    
    如果使用者想要將通知發給**群組**，可以選擇一個你以前曾經加入過的聊天室。
    
    選取完畢後，按下 **同意並連動** 按鈕即可完成訂閱，此時使用者會立即收到 **與「*服務名稱*」連動完成** 的通知訊息！
    
3.  此時瀏覽器會主動發出 HTTP POST 要求到 `redirect_uri` 指定的網址，並且帶入 `code` 與 `state` 表單欄位！
    

### 訊息接收者 (接受訊息方) 要做的事

如果訊息接收者是**自己** (`透過1對1聊天接收LINE Notify的通知`)，那麼這一步什麼都不用做。

如果訊息接收者是**群組** (聊天室)，那麼你還必須將 `@linenotify` (LINE Notify) 這個官方帳號加入到該聊天室才能收到通知！

### 發送推播訊息

1.  取得授權碼 ( `code` )
    
    當 **授權通知方** 按下 **同意並連動** 按鈕之後，使用者的瀏覽器會直接對 `redirect_uri` 所設定的網址發出 HTTP POST 要求。由於我們透過 ngrok 產生的暫時網址會幫我們接收 HTTP POST 要求，所以你可以透過 `http://127.0.0.1:4040/` 得知 HTTP POST 傳入的內容，其中就有 `code` 欄位可用，請將其值複製下來！
    
    ![2020-02-18\_03-03-09](https://stwillblogassets.blob.core.windows.net/files/images/external/user-images.githubusercontent.com/8def2275fe7497b263a4-74680357-48e79880-51fb-11ea-803c-f8a2fa235cb2.png)
    
2.  取得存取權杖 ( `access_token` ) (Access Token)
    
    安裝 [curl](https://chocolatey.org/packages/curl) 工具 (使用 [Chocolatey](https://chocolatey.org/install) 套件管理器)
    
    ```bash
    choco install curl -y
    ```
    
    你必須發送一個 HTTP POST 到 `https://notify-bot.line.me/oauth/token` 才能取得存取權杖，命令如下：
    
    ```bash
    curl -d "grant_type=authorization_code&redirect_uri=https://xxxxxxxx.ngrok.io&client_id=xxxxxxxxxxxxxxxxxxxxxxx&client_secret=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&code=xxxxxxxxxxxxxxxxxxxxxx" https://notify-bot.line.me/oauth/token
    ```
    
    參數說明如下：
    
    -   `grant_type`: 固定寫 `authorization_code` 就對了。
    -   `redirect_uri`: 請設定你 [ngrok](https://ngrok.com/) 產生的暫時網址。
    -   `client_id`: 登錄服務的 `Client ID` 資訊
    -   `client_secret`: 登錄服務的 `Client Secret` 資訊
    -   `code`: 上個步驟取得的授權碼 ( `code` )
    
    如果有成功發出 Access Token 你將會得到以下 JSON 內容：
    
    ```json
    {
      "status": 200,
      "message": "access_token is issued",
      "access_token":"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
    }
    ```
    
    > 任何人拿到 **存取權杖** 後，就可以透過該**權杖**發送推播通知給訂閱的目標 (`USER` 或 `GROUP`)
    
    如果失敗會得到以下 JSON 內容：
    
    ```json
    {
      "status": 400,
      "message": "invalid code",
      "access_token": null
    }
    ```
    
3.  發送 LINE Notify 通知訊息
    
    任何通知訊息都需要有 Access Token 才能發出！
    
    你可以透過以下 curl 命令發出 LINE Notify 通知訊息：
    
    ```bash
    curl -H "Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" -d "message=Hello World" https://notify-api.line.me/api/notify
    ```
    
    這裡的 `-H` 參數代表著 HTTP POST 的一個自訂標頭 (Custom Header)，而 `Authorization` 則是用來通過身分驗證用的標頭，而 `Bearer` 則代表我們將傳入一個 **[Bearer Token](https://oauth.net/2/bearer-tokens/)**，後面的 `xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx` 就是我們在上一步取得的 Access Token 存取權杖。
    
    如果成功發出訊息，你會得到以下 JSON 回應，並且在 LINE App 上也會即時收到通知訊息：
    
    ```json
    {
      "status": 200,
      "message": "ok"
    }
    ```
    
    如果 Access Token 已經被撤銷，則會得到以下回應：
    
    ```json
    {
      "status": 401,
      "message": "Invalid access token"
    }
    ```
    
4.  取得目前 Access Token 狀態
    
    只要對 `https://notify-api.line.me/api/status` 發出 GET 要求即可獲得 Access Token 狀態：
    
    ```bash
    curl -H "Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" https://notify-api.line.me/api/status
    ```
    
    以下是 Access Token 有效的回應內容：
    
    ```json
    {
      "status": 200,
      "message": "ok",
      "targetType": "USER",
      "target": "Will"
    }
    ```
    
    > 備註：上述 `targetType` 可能的值有 `USER` (用戶) 或 `GROUP` (聊天室)。
    
    如果 Access Token 已經被撤銷，則會得到以下回應：
    
    ```json
    {
      "status": 401,
      "message": "Invalid access token"
    }
    ```
    
    如果想得知目前 Access Token 的 [API Rate Limit](https://notify-bot.line.me/doc/en/) 相關資訊，可以改用以下命令查詢：
    
    ```bash
    curl -D - -H "Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" https://notify-api.line.me/api/status
    ```
    
    這裡的 `-D -` 代表將 Response Headers 全部輸出到 STDOUT 螢幕上，這時你會得到以下資訊：
    
    ```log
    HTTP/1.1 200
    Server: nginx
    Date: Mon, 17 Feb 2020 15:33:26 GMT
    Content-Type: application/json;charset=UTF-8
    Transfer-Encoding: chunked
    Connection: keep-alive
    Keep-Alive: timeout=3
    X-RateLimit-Limit: 1000
    X-RateLimit-ImageLimit: 50
    X-RateLimit-Remaining: 998
    X-RateLimit-ImageRemaining: 50
    X-RateLimit-Reset: 1581953606
    ```
    
    其中的 `X-RateLimit-Remaining` 就是你這個 Token 在這一個小時內還能用幾次。
    
    還有 `X-RateLimit-Reset` 代表著下次 Reset 用量限制的時間點，這是 [UTC epoch seconds](https://en.wikipedia.org/wiki/Unix_time) 單位。
    
    若要在 Linux 下查詢這個數字所代表的時間點，可以輸入以下命令查詢：
    
    ```bash
    date -d @1581953606
    ```
    
    若要在 PowerShell 下查詢這個數字所代表的時間點，可以輸入以下命令查詢：
    
    ```powershell
    (([System.DateTimeOffset]::FromUnixTimeSeconds(1581953606)).DateTime.ToLocalTime()).ToString("s")
    ```
    
5.  撤銷目前 Access Token
    
    只要對 `https://notify-api.line.me/api/revoke` 發出 POST 要求即可撤銷 Access Token：
    
    ```bash
    curl -X POST -H "Authorization: Bearer xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" https://notify-api.line.me/api/revoke
    ```
    
    以下是成功撤銷 Access Token 的回應內容：
    
    ```json
    {
      "status": 200,
      "message": "ok"
    }
    ```
    
    如果 Access Token 本來就無效，則會得到以下回應：
    
    ```json
    {
      "status": 401,
      "message": "Invalid access token"
    }
    ```
    

### 相關連結

-   [LINE Notify API Document](https://notify-bot.line.me/doc/en/)
-   [LINE Notify 已連動的服務](https://notify-bot.line.me/my/)
