前回は、LINE WORKS の Developer Console で、オウム返し Bot の作成準備を行いました。
今回は、いよいよ Azure Functions で、Bot 本体を準備していきます。
まずは、Azure Portal へアクセスし、リソースの作成
から関数アプリを作成します。
ランタイム スタックには PowerShell Core
を選択します。
今回は、お手軽に試せるということで、プランの種類として
消費量(サーバーレス)
を選択しました。このプランでは、アクセスがが来てから環境を起動し、しばらくアクセスが無いと環境を終了します。
このため、メッセージを受けてからボットがオウム返しするまで、若干 (30秒程度?) 時間がかかることがあります。
LINE WORKS の処理が遅いのではなく、消費量(サーバーレス)
プランを利用した Azure Functions の制約ですので、その旨ご理解ください m(_,_)m
[確認および作成] をクリックして先に進みましょう。デプロイの完了まで数分かかります。
作成された関数アプリに移動します。見つからない場合には、[すべてのサービス]-[すべてのリリース]から見つけます。
さて、これまでは、PowerShell での JWT の処理には powershell-jwt をインストールして利用してきました。Azure Function で PowerShell Module を使う場合には、モジュールをインストールするのではなく、Save-Module
Cmdlet で実行環境に保存する必要があります。
まずは、[開発ツール]-[高度なツール]-[移動] から Kudu に移動します。
[Debug Console]-[PowerShell] で PowerShell コンソールを開きます。
コンソール領域に以下のコマンドを入力します
cd site\wwwroot
mkdir modules
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
Install-PackageProvider nuget -Force -Scope CurrentUser
Save-Module powershell-jwt -Path .\modules
さらに、LINE WORKS の Developers Console でダウンロードした PrivateKey ファイルの拡張子を txt に変更し、ページ上部ファイル・フォルダ領域にドラッグアンドドロップして、アップロードします。(拡張子が .key のフィルはアップロードができないようです。)
認証に必要な情報は、PowerShell 内にベタに書くこともできますが、せっかくなので、Azure Functions の環境変数を利用してみましょう。
[設定]-[構成]から[アプリケーション設定] タブを開き、[新しいアプリケーション設定]をクリックして LINE WORKS の Developers Console で取得した認証に必要な情報を保存していきます。最期に[保存]ボタンをクリックするのを忘れないでください。
名前 | 取得元 | 例 |
---|---|---|
BOTID | BotID (BotNo) | 1234567 |
CLIENTID | Client ID | A0B1c3d4e5f6g7h8I9 |
CLIENTSECRET | Client Secet | AbCdEfGhIj |
SERVICEACCOUNT | Service Account | abcde.serviceaccount@yourcompany |
PRIVATEKEYFILE | アップロードしたPrivateKeyFile名 | private_20220101123456.txt |
BOTSECRET | Bot Secret | lkjlekjlkjSLJKDLKDJLElkjl |
ここまできたらあと一息。[関数]-[関数]-[作成] で関数を作成します。
開発環境は [ポータルでの開発] を選択し、テンプレートには [HTTP trigger] を選びます。
作成された [HttpTrigger1] へ移動し、[コードとテスト] をクリックするとエディタが開きますので、
次のコードでまるっと置き換えて保存します。
using namespace System.Net
param($Request, $TriggerMetadata)
$clientId = $env:CLIENTID
$clientSecret = $env:CLIENTSECRET
$privateKeyFile = $env:PRIVATEKEYFILE
$svcAccount = $env:SERVICEACCOUNT
$botSecret = $env:BOTSECRET
$Scope = "bot"
$body = $Request.RawBody
$receiveMsg = $body | convertfrom-json
# GET Access Token
$PrivKeyPath = "D:\home\site\wwwroot\" + $privateKeyFile
$rsaPrivateKey = Get-Content $PrivKeyPath -AsByteStream
$iat = [int](Get-Date -UFormat %s)
$exp = $iat + 3600
$payload = @{
sub = $SvcAccount
iat = $iat
}
$jwt = New-JWT -Algorithm 'RS256' -SecretKey $rsaPrivateKey -PayloadClaims $payload -ExpiryTimestamp $exp -Issuer $clientId
$requestHeader = @{
'Content-Type' = 'application/x-www-form-urlencoded'
}
$requestBody = @{
assertion = $jwt
grant_type = 'urn:ietf:params:oauth:grant-type:jwt-bearer'
client_id = $clientId
client_secret = $clientSecret
scope = $Scope
}
$url = 'https://auth.worksmobile.com/oauth2/v2.0/token'
$response = Invoke-RestMethod -Uri $url -Method POST -Headers $requestHeader -Body $requestBody
$sectoken = ConvertTo-SecureString $response.access_token -AsPlainText
# Signature check
$oHMACSHA256 = New-Object System.Security.Cryptography.HMACSHA256
$oHMACSHA256.key = [Text.Encoding]::ASCII.GetBytes($BotSecret)
$readBuf = [System.Text.Encoding]::UTF8.GetBytes($body)
$signature_rawout = $oHMACSHA256.ComputeHash($readBuf)
$signatureB64 = [Convert]::ToBase64String($signature_rawout)
if ($signatureB64.ToString() -eq $Request.Headers["X-Works-Signature"]) {
$msg = $receiveMsg.content.text
}
else {
$msg = "怪しい奴め!"
}
# オウム返しするぞ
$reqBody =@{
content = @{
type = 'text'
text = $msg
}
}
$reqBody = $reqBody | convertto-json
$reqBody = [System.Text.Encoding]::UTF8.GetBytes($reqBody ) # hack for MOJI-BAKE
$userId = $receiveMsg.source.userId
$botId = $Request.Headers["X-Works-BotId"]
$URL = "https://www.worksapis.com/v1.0/bots/$botId/users/$userId/messages"
Invoke-WebRequest -Method POST -Uri $URL -body $reqBody -Authentication Bearer -Token $secToken -ContentType "application/json"
コードを見ても、1/3 が AccessToken 取得、1/3 が Signature のチェックで、実際に Bot メッセージを送っている部分は本当に簡単ですね。
右上の [関数URLの取得] で、Azure Functions で作成した関数を呼び出すための URL を取得しておきます。
最期にもう一度 LINE WORKS の Developer Console へ行き、Callback URL を有効にして先程保存した URL を貼り付けます。送信可能なメッセージタイプに テキスト
を指定します。
オウム返し Bot の作成作業は以上です。
オウム返し Bot に話しかけると、そっくりそのまま返してくれます。
Bot Secret について
Bot へのメッセージ送信は、Callback URL さえわかっていれば、認証もなく誰でもアクセスすることができます。
Bot に対して発行される Bot Secret を用いてメッセージのハッシュを計算し、X-WORKS-Signature ヘッダーの値と比較することで、本当に LINE WORKS から送られたメッセージであるかを検証することができます。
運用環境で Bot の Callback を利用する場合には、メッセージの検証を必ず行うようにしてください。