[RAILS] So erstellen Sie eine mit Ruby erstellte LINE-Messaging-Funktion

Einführung

Ich hatte die Gelegenheit, eine Funktion zum Austausch von Nachrichten zwischen einem in Ruby geschriebenen System und LINE, einem allgemeinen Benutzer, zu entwickeln, damit ich das damals gewonnene Wissen weitergeben kann.

Ich habe auch eine Demo einer funktionierenden Anwendung mit Rails erstellt. Ausführliche Informationen zur Implementierung finden Sie unter hier. Ich denke, dass der Inhalt des Artikels reibungslos eingehen wird, wenn Sie fragen.

Was zu machen

Ein Systemadministrator (im Folgenden als "Administrator" bezeichnet) und ein allgemeiner Benutzer (im Folgenden als "Benutzer" bezeichnet) erstellen eine Funktion zum Austausch von Textnachrichten über LINE. Da das System die LINE-Informationen des Benutzers kennen muss, um tatsächlich kommunizieren zu können, implementieren wir auch die LINE-Anmeldung im Browser.

Wenn der Benutzer nach dem Verknüpfen der LINE-Informationen des Benutzers eine Nachricht an das mit dem Administrator verknüpfte offizielle LINE-Konto sendet, wird die Nachricht von Webhook an das System gesendet und von dort in der Datenbank gespeichert. Das Bild entspricht in etwa der Abbildung unten. Untitled Diagram (1).png

Der Administrator kann auch LINE-Nachrichten über das System an Benutzer senden. Wenn Sie einen Text vom System senden, können Sie über das Programm eine Nachricht vom offiziellen LINE-Konto des Administrators an den Zielbenutzer senden. Nach dem Senden wird die Nachricht in der Datenbank gespeichert. Das Bild ist wie folgt. Untitled Diagram (2).png

Arbeiten im Voraus erforderlich

Erstellen Sie einen Kanal für die LINE-API

Wenn der Administrator keinen LINE-API-Kanal hat, ist es nicht möglich, über LINE mit Benutzern zu kommunizieren. Erstellen Sie ihn daher. Machen wir es von LINE Developer Console. Der Kanal, den Sie dieses Mal erstellen müssen

Es gibt zwei.

Die Messaging-API fungiert als offizielles LINE-Konto. Als Einschränkung setzen wir den ** Antwortmodus auf "Bot" **. Im Chat-Modus kann ich vom offiziellen LINE-Account-Manager aus kommunizieren, aber keine Webhooks empfangen. Daher muss es im Bot-Modus verwendet werden, da das Problem besteht, dass das System kein Protokoll der Interaktion führen kann. Klicken Sie hier, um Details zum Erstellen zu erhalten (https://developers.line.biz/ja/docs/messaging-api/getting-started/#%E3%83%81%E3%83%A3%E3%83%8D% E3% 83% AB% E3% 81% AE% E4% BD% 9C% E6% 88% 90) Bitte. LINE Login ist buchstäblich ein Kanal für die Verwendung von LINE Login.

Erstellen Sie nach dem Erstellen die Daten in der Admins-Tabelle der Datenbank. Ursprünglich denke ich, dass es gut ist, sich vom Bildschirm aus zu registrieren, aber es ist dazu gedacht, es seitlich zu tragen und direkt von der Konsole aus zu stecken (wenn Sie es mit dem Produktionscode in die Datenbank stellen, wird empfohlen, es aus Sicherheitsgründen verschlüsselt zu platzieren. Machen)

  create_table "admins", options: "ENGINE=InnoDB DEFAULT CHARSET=utf8mb4", force: :cascade do |t|
    t.integer "line_messaging_id", null: false #Messaging-API "Kanal-ID"
    t.string "line_messaging_secret", null: false #Messaging-API "Channel Secret"
    t.string "line_messaging_token", null: false #Messaging-API "Channel Access Token"
    t.integer "line_login_id", null: false #"Channel ID" von LINE Login
    t.string "line_login_secret", null: false #LINE Login "Channel Secret"
    t.datetime "created_at", precision: 6, null: false
    t.datetime "updated_at", precision: 6, null: false
  end

Stellen Sie verschiedene URLs ein

Das nächste Mal muss ich einige URLs auf der Konsolenseite von LINE festlegen, damit ich mich registrieren kann. Insbesondere ist es wie folgt.

Bei der Registrierung dieser URL sind einige Dinge zu beachten. Es hat eine URL

--https nur --localhost nicht verfügbar

Das ist der Punkt. Bei dieser Geschwindigkeit scheint die lokale Entwicklung schwierig zu sein. Mit ngrok können Sie die lokale URL jedoch vorübergehend nach außen veröffentlichen, sodass Sie sie bequem lokal entwickeln können, indem Sie die damit erstellte URL registrieren. Du kannst es schaffen. Es ist sehr praktisch.

Nachdem Sie den POST-Anforderungspfad für die Webhook-URL erstellt und in der Konsole festgelegt haben, überprüfen Sie die Anforderung über die Schaltfläche "Überprüfen". Stellen Sie sicher, dass Sie 200 Antworten erhalten. Weitere Informationen [hier](https://developers.line.biz/ja/docs/messaging-api/building-bot/#%E3%82%B3%E3%83%B3%E3%82%BD%E3% 83% BC% E3% 83% AB% E3% 81% A7% E3% 83% 9C% E3% 83% 83% E3% 83% 88% E3% 82% 92% E8% A8% AD% E5% AE% 9A% E3% 81% 99% E3% 82% 8B) Bitte.

Nachdem die Vorbereitungen für die Entwicklung abgeschlossen sind, möchte ich sie weiterentwickeln.

Verknüpfen Sie das LINE-Konto des Benutzers mit dem System

Zunächst möchte ich eine LINE-Anmeldefunktion erstellen, um die zum Senden und Empfangen von Nachrichten erforderlichen LINE-Informationen des Benutzers in die Datenbank zu stellen. Diese LINE-Information ist die "Benutzer-ID". Bitte beachten Sie, dass es sich nicht um die bei der ID-Suche verwendete LINE-ID handelt.

Der Anmeldefluss ist [hier](https://developers.line.biz/ja/docs/line-login/integrate-line-login/#%E3%83%AD%E3%82%B0%E3%82% A4% E3% 83% B3% E3% 81% AE% E3% 83% 95% E3% 83% AD% E3% 83% BC), aber wenn ich es noch einmal schreibe

  1. Leiten Sie den Benutzer mit den erforderlichen Abfrageparametern vom System zur Autorisierungs-URL für die LINE-Anmeldung
  2. Der LINE-Anmeldebildschirm wird im Browser geöffnet, und der Benutzer meldet sich an und wird authentifiziert.
  3. Leiten Sie Benutzer von der LINE-Plattform über redirect_uri zum System um. Zu diesem Zeitpunkt wird auch eine Abfragezeichenfolge mit dem Autorisierungscode und dem Status an das System gesendet.
  4. Nach der Überprüfung des Status verwendet das System den Autorisierungscode, um ein Zugriffstoken von der Endpunkt-URL https://api.line.me/oauth2/v2.1/token anzufordern.
  5. Die LINE-Plattform überprüft die Anforderung vom System und gibt ein Zugriffstoken zurück.
  6. Rufen Sie die Social API basierend auf dem Zugriffstoken auf, um die Benutzer-ID abzurufen und in der Datenbank zu speichern.

Schauen wir uns den Code an, mit dem die Autorisierungs-URL für Schritt 1 erstellt wird.

app/controllers/auth_controller.rb


class AuthController < ApplicationController
  def index
    admin = Admin.find(params[:admin_id])

    state = SecureRandom.hex(32)
    session[:state] = state
    redirect_to Line::Api::Oauth.new(admin).auth_uri(state)
  end
end

/ admin /: admin_id / auth leitet basierend auf den LINE-Anmeldekontoinformationen des Zieladministrators zur Autorisierungs-URL weiter. Da für CSRF-Maßnahmen ein Status erforderlich ist, wird auf der Anwendungsseite eine Zufallszahl generiert. Der Wert wird in der Sitzung gespeichert (wird bei der Verarbeitung nach der Autorisierung verwendet) und an Line :: Api :: Oauth # auth_uri übergeben. Werfen wir einen Blick auf den darin enthaltenen Code.

app/models/line/api/oauth.rb


AUTH_URI = 'https://access.line.me/oauth2/v2.1/authorize'

def auth_uri(state)
  params = {
    response_type: 'code',
    client_id: @admin.line_login_id,
    redirect_uri: callback_uri,
    state: state,
    scope: 'openid',
    prompt: 'consent', #Option, um sicherzustellen, dass die LINE-Authentifizierung zulässig ist
    bot_prompt: 'aggressive' #Nach dem Anmelden wird ein Bildschirm angezeigt, in dem Sie gefragt werden, ob Sie sich mit dem offiziellen Konto anfreunden möchten, mit dem Sie verknüpft sind.
  }

  # NOTE: https://developers.line.biz/ja/docs/line-login/integrate-line-login/#making-an-authorization-request
  "#{AUTH_URI}?#{params.to_query}"
end

Die detaillierte Bedeutung der Parameter finden Sie unter hier. Persönlich ist der Parameter "bot_prompt" praktisch, und nach dem Anmelden bei LINE wird auch der Bildschirm zum Hinzufügen von Freunden des entsprechenden offiziellen Kontos angezeigt. Daher hielt ich es für zweckmäßig, Nachrichten voneinander und voneinander zu bringen.

Wenn Sie auf die URL klicken, werden Sie zum Anmeldebildschirm weitergeleitet (siehe Abbildung unten).

スクリーンショット 2020-06-16 1.52.14.png

Wenn die Anmeldung abgeschlossen und die Autorisierung abgeschlossen ist, werden Sie zu der zuvor festgelegten LINE-Anmelde-Rückruf-URL weitergeleitet. Nun, da wir zu / admin /: admin_id / callback gehen, schauen wir uns den entsprechenden Code an.

app/controllers/callback_controller.rb


class CallbackController < ApplicationController
  def index
    admin = Admin.find(params[:admin_id])

    #Wirf eine Ausnahme aus, wenn die Zustände unterschiedlich sind
    raise Line::InvalidState unless params[:state] == session[:state]

    line_user_id = Line::Api::Oauth.new(admin).line_user_id(params[:code])
    User.create!(line_user_id: line_user_id)

    render plain: 'LINE-Zusammenarbeit abgeschlossen!', status: :ok
  end
end

CSRF-Maßnahmen werden ergriffen, indem der Wert des Status nach der Autorisierung mit dem Wert des Status der zuvor eingegebenen Sitzung verglichen wird. Danach erhalten Sie die LINE-Benutzer-ID. Speichern Sie es nach dem Erhalt in der Datenbank. Werfen wir einen Blick auf den Code zur Erfassung der Benutzer-ID.

app/models/line/api/oauth.rb


def line_user_id(code)
  verify_id_token(access_token_data(code))['sub']
end

def access_token_data(code)
  req_body = {
    grant_type: 'authorization_code',
    code: code,
    redirect_uri: callback_uri, # NOTE:Es wird mit der in der Konsole des LINE-Anmeldekanals festgelegten "Rückruf-URL" verglichen.
    client_id: @admin.line_login_id,
    client_secret: @admin.line_login_secret
  }

  # NOTE: https://developers.line.biz/ja/docs/line-login/integrate-line-login/#get-access-token
  res = conn.post do |req|
    req.url '/oauth2/v2.1/token'
    req.headers['Content-Type'] = 'application/x-www-form-urlencoded'
    req.body = req_body
  end
  JSON.parse(handle_error(res).body)
end

def verify_id_token(access_token_data)
  req_body = {
    id_token: access_token_data['id_token'],
    client_id: @admin.line_login_id
  }
  # NOTE: https://developers.line.biz/ja/reference/social-api/#verify-id-token
  res = conn.post do |req|
    req.url '/oauth2/v2.1/verify'
    req.body = req_body
  end
  JSON.parse(handle_error(res).body)
end

Klicken Sie auf Access Token Acquisition API mit access_token_data, um die Informationen zurückzugeben, und dann Wenn Sie die Social API ID Token Verification API aufrufen und erfolgreich sind, erhalten Sie Ihre Benutzer-ID.

Beachten Sie, dass die API für die Erfassung von Zugriffstoken "redirect_uri" übergibt, was genau mit dem im Autorisierungs-URI festgelegten "redirect_uri" übereinstimmen sollte. Sie können nicht viel tun, aber aus verschiedenen Gründen, wenn Sie beim Erstellen einer Autorisierungs-URL etwas als Abfrageparameter an redirect_uri übergeben und mit einem Rückruf abrufen möchten, enthält die API für die Erfassung von Zugriffstoken diesen Abfrageparameter Wenn Sie es nicht an "redirect_uri" übergeben, wird ein Fehler angezeigt.

Empfangen Sie die Nachricht des Benutzers im System

Nachdem der Benutzer nun eine Verknüpfung mit dem offiziellen LINE-Konto des Administrators herstellen konnte, möchte ich als nächstes die vom Benutzer im System gesendete LINE-Nachricht erhalten. Da die URL des Pfads "/ admin /: admin_id / webhook" in der Webhook-URL der Messaging-API angegeben ist, wird die Anforderung jedes Mal gesendet, wenn ein Ereignis (Freund hinzufügen, Nachricht blockieren usw.) im offiziellen Konto auftritt. Werden. Wenn also das Ereignis, das die ** Nachricht von dieser Anfrage gesendet hat, und die Person, die sie gesendet hat, die in der Datenbank gespeicherte LINE-Benutzer-ID ** ist, werden die LINE-Nachrichten vom Benutzer gesammelt, wenn Sie die Nachricht in der DB speichern. Sie können. Der Code für den Webhook-Controller ist unten.

app/controllers/webhook_controller.rb


class WebhookController < ApplicationController
  protect_from_forgery with: :null_session

  def create
    admin = Admin.find(params[:admin_id])

    bot = Line::Api::Bot.new(admin)
    body = request.body.read
    raise Line::InvalidSignatureError unless bot.validate_signature?(body, request.env['HTTP_X_LINE_SIGNATURE'])

    events = bot.parse_events_from(body)
    events.each do |event|
      case event
      when Line::Bot::Event::Message
        Line::SaveReceivedMessage.new(admin).call(event)
      end
    end

    render plain: 'success!', status: :ok
  end
end

Da die Anforderung von außen kommt, machen Sie das CSRF-Token ungültig. Darüber hinaus müssen Sie Signaturvalidierung durchführen, um festzustellen, ob die Anforderung von der LINE-Plattform stammt. Es ist ein wenig kompliziert, aber es wird mit einem Edelstein namens line-bot-sdk-ruby gemacht, also lasst es uns verwenden.

Stellen Sie nach der Überprüfung fest, wie das Ereignis aussieht. Ich werde es verwenden, weil der Edelstein auch die Ereignisinformationen aus dem Anfragetext analysiert. Ich denke, es ist einfach, Ereignisse mit einer case-Anweisung zu verzweigen. Da "Line :: Bot :: Event :: Message" das Ereignis ist, bei dem die Nachricht eintrifft, wird zu diesem Zeitpunkt der Vorgang zum Speichern der Nachricht eingefügt. Der Code ist unten.

app/models/line/save_received_message.rb


module Line
  class SaveReceivedMessage
    def initialize(admin)
      @admin = admin
    end

    def call(event)
      user = User.find_by(line_user_id: event['source']['userId'])

      resource = MessageText.new(content: event.message['text'])
      Message.create!(sendable: user, receivable: @admin, resource: resource) if user.present?
    end
  end
end

Siehe hier für den Inhalt des Ereignisobjekts.

Überprüfen Sie abschließend die Funktion. iOS_の画像.png Wenn Sie eine Nachricht senden

スクリーンショット_2020-06-16_13_02_20.png Sie können sehen, dass die Anforderung übersprungen und der Datensatz gespeichert wird. Das System kann nun die LINE-Nachricht des Benutzers empfangen und in die Datenbank stellen.

Senden Sie eine Nachricht vom System an den Benutzer

Als nächstes betrachten wir die LINE-Nachrichtenübertragung von System-> Benutzer, die das Gegenteil der vorherigen ist. Sie müssen Webhook nicht verwenden, drücken Sie einfach API zum Senden einer Push-Nachricht und fertig.

app/models/line/save_sent_message.rb


module Line
  class SaveSentMessage
    def initialize(admin)
      @admin = admin
    end

    def call_with_text(user:, text:)
      user = User.find_by(line_user_id: user.line_user_id)

      if user.present?
        Line::Api::Push.new(@admin).call_with_text(user: user, text: text)
        resource = MessageText.new(content: text)
        Message.create!(sendable: @admin, receivable: user, resource: resource)
      end
    end
  end
end

app/models/line/api/push.rb


module Line::Api
  class Push < Base
    def call_with_text(user:, text:)
      call(user: user, resource: Message::Text.new([text]))
    end

    private

    def call(user:, resource:)
      req_body = {to: user.line_user_id}.merge(resource.request_body)
      # NOTE: https://developers.line.biz/ja/reference/messaging-api/#send-push-message
      res = conn.post do |req|
        req.url '/v2/bot/message/push'
        req.headers['Content-Type'] = 'application/json'
        req.headers['Authorization'] = "Bearer #{@admin.line_messaging_token}"
        req.body = req_body.to_json
      end

      handle_error(res)
    end
  end
end

Es ist eine Funktionsprüfung. Tragen Sie es seitlich und schlagen Sie den Akkord von der Konsole aus.

スクリーンショット_2020-06-18_8_13_23.png Ein Datensatz wurde hinzugefügt.

iOS_の画像__1_.png

Eine Nachricht wurde an LINE gesendet!

schließlich

Mit dem oben Gesagten ist es möglich, zwischen dem Benutzer und dem System miteinander zu kommunizieren und den Inhalt zu verlassen. Ich denke, dass es in einem realen System komplizierter sein wird, aber ich hoffe, dies wird Ihnen helfen, etwas umzusetzen: beten Sie:

Recommended Posts

So erstellen Sie eine mit Ruby erstellte LINE-Messaging-Funktion
Ruby mit AtCoder lernen 13 So erstellen Sie ein zweidimensionales Array
So implementieren Sie TextInputLayout mit Validierungsfunktion
Einfacher LINE BOT mit Java Servlet
Wie man ein schattiertes Glas macht
Machen wir einen LINE Bot mit Ruby + Sinatra - Teil 2
Machen wir einen LINE Bot mit Ruby + Sinatra - Teil 1
[Java] So unterbrechen Sie eine Zeile mit StringBuilder
Java zum Spielen mit Function
Java - So erstellen Sie JTable
So fügen Sie die ActionText-Funktion hinzu
Verwendung von Ruby return
[Ruby] Wie man auskommentiert
Wie man mit html.erb nummeriert (nummeriert)
So aktualisieren Sie mit activerecord-import
Ruby: Wie man Cookies benutzt
[Schienen] Wie man Samen macht
Vergleich des Schreibens von Callback-Funktionen (Java, JavaScript, Ruby)
[Einfach] So formatieren Sie Ruby erb-Dateien automatisch mit vsCode
Ich möchte eine Funktion mit Kotlin und Java erstellen!
So erstellen Sie eine App mit Tensorflow mit Android Studio
Umgang mit verschiedenen Versionen von rbenv und Ruby
Ich möchte mit link_to [Hinweis] eine Schaltfläche mit einem Zeilenumbruch erstellen.
Wie fange ich mit schlank an?
Wie man in Ruby auf unbestimmte Zeit iteriert
Ich möchte eine Browsing-Funktion mit Ruby on Rails hinzufügen
So erstellen Sie eine JAR-Datei ohne Abhängigkeiten in Maven
So erstellen Sie einen Java-Container
So installieren Sie Ruby über rbenv
So erstellen Sie eine App mit Ruby on Rails (vorausgesetzt, die Umgebung wurde erstellt)
Wie man ein Zeichen mit "~" einschließt
Verwendung von Ruby on Rails
So erstellen Sie einen JDBC-Treiber
So installieren Sie Bootstrap in Ruby
Wie schreibe ich Ruby, wenn in einer Zeile Zusammenfassung vom Anfänger
Wie man mssql-tools mit alpine benutzt
So erstellen Sie einen Begrüßungsbildschirm
So erstellen Sie ein Jenkins-Plug-In
Wie erstelle ich ein Maven-Projekt?
So fügen Sie die Löschfunktion hinzu
[Für Anfänger] So erhalten Sie den Namen der Ruby-Eisenbahnlinie
Ruby mit AtCoder lernen 11 So erhalten Sie häufig verwendete Standardeingaben
Verwendung der Ruby-Inject-Methode
So erstellen Sie ein Java-Array
Verwendung von MinIO mit derselben Funktion wie S3 Verwenden Sie Docker-Compose
[Android] So erstellen Sie ein Dialogfragment
Wie man Ruby's irb ausführt (interaktiver Ruby)
So starten Sie Camunda mit Docker
Ich habe versucht, mit Rails eine Gruppenfunktion (Bulletin Board) zu erstellen