[RUBY] [Rails] Erhalten Sie access_token zum Zeitpunkt der Twitter-Authentifizierung mit Sorcery und speichern Sie es in der Datenbank

Was ist dieser Artikel?

Wenn Sie die Twitter-API verwenden, können Sie Ihr eigenes (registriertes Konto) access_token, access_token_secret ↓ verwenden, um öffentliche Benutzerinformationen und Tweets abzurufen. スクリーンショット 2020-10-05 8.23.35.png Sie müssen jedoch für jeden Benutzer ein eindeutiges access_token und access_token_secret verwenden, um Informationen über private Benutzer abzurufen und um über die App zu twittern. In diesem Artikel werde ich eine Implementierung schreiben, die das access_token und das access_token_secret einzelner Benutzer in der Datenbank speichert und verwendet.

Es wird davon ausgegangen, dass die Twitter-Authentifizierung in [Rails] Sortery für die Twitter-Authentifizierung \ -Qiita implementiert wurde.

【Hinweis】 In diesem Artikel wird davon ausgegangen, dass zum Zeitpunkt der Implementierung keine Benutzer vorhanden sind. Wenn Sie bereits einen Benutzer haben (wenn Sie die Benutzerdaten nicht zurücksetzen können), ist das access_token dieses Benutzers null, sodass Sie eine lästige bedingte Verzweigung hinzufügen müssen.

Umgebung

Ruby 2.6.6 Rails 5.2.4.3 Sorcery 0.15.0

Modellzuordnungen ändern

In meinem Fall habe ich angenommen, dass die externe Authentifizierung nur für Twitter gilt, daher habe ich die Zuordnung wie folgt in "has_one" geändert.

app/models/user.rb


class User < ApplicationRecord
  authenticates_with_sorcery!
- has_many :authentications, dependent: :destroy
- accepts_nested_attributes_for :authentications
+ has_one :authentication, dependent: :destroy
+ accepts_nested_attributes_for :authentication
  ...
end

Wenn Sie mit anderen Diensten arbeiten und der Benutzer has_many: authentications hat, ersetzen Sie die Beschreibung wie "user.authentication.hoge" durch "user.authentications.find_by! (Anbieter:" twitter ").

Erstellen einer Migrationsdatei

Fügen Sie der Authentifizierungstabelle die Spalten access_token und access_token_secret hinzu. Wenn Sie einen anderen Link als Twitter verwenden, entfernen Sie das optionale "null: false".

db/migrate/20200613022618_add_access_token_columns_to_authentications.rb


class AddAccessTokenColumnsToAuthentications < ActiveRecord::Migration[5.2]
  def change
    add_column :authentications, :access_token, :string, null: false
    add_column :authentications, :access_token_secret, :string, null: false
  end
end

Controller hinzufügen

Was sich gegenüber dem vorherigen Artikel geändert hat, ist das Innere der Methode "create_user_from".

app/controllers/api/v1/oauths_controller.rb


class OauthsController < ApplicationController
  skip_before_action :require_login # applications_vorher mit Controller_action :require_Wenn Login gesetzt ist

  def oauth
    login_at(auth_params[:provider])
  end

  def callback
    provider = auth_params[:provider]
    if auth_params[:denied].present?
      redirect_to root_path, notice: "Ich habe meinen Login storniert"
      return
    end
    #Erstellen Sie einen neuen Benutzer, wenn Sie sich nicht mit den gesendeten Anmeldeinformationen anmelden können (falls kein solcher Benutzer vorhanden ist).
    create_user_from(provider) unless (@user = login_from(provider))
    redirect_to root_path, notice: "#{provider.titleize}Ich habe mich mit angemeldet"
  end

  private

  def auth_params
    params.permit(:code, :provider, :denied)
  end

  def create_user_from(provider)
    @user = build_from(provider) # ①
    @user.build_authentication(uid: @user_hash[:uid],
                               provider: provider,
                               access_token: access_token.token,
                               access_token_secret: access_token.secret) # ②
    @user.save! # ③
    reset_session
    auto_login(@user)
  end

Build build_from ist eine Methode der Zauberei. Fügen Sie die von provider (: twitter) an Sorcery übergebenen Daten als Attribute der Benutzerinstanz (@ user) ein.

② Erstellen Sie eine Authentifizierungsinstanz. Da "@ user_hash" und "access_token" die von Twitter empfangenen Daten enthalten, verwenden Sie diese. Übrigens ist build_authentication eine Methode von has_one. Im Fall von has_many setzen Sie sie bitte auf user.authentications.build.

[11] pry(#<OauthsController>)> @user_hash
=> {:token=>"111111111111111111111",
 :user_info=>
  {"id"=>1048451188209770497,
   "id_str"=>"1048451188209770497",
   "name"=>"END",
   "screen_name"=>"aiandrox",
   "location"=>"Okayama die ganze Zeit → Yamanashi ein wenig → Tokyo Imakoko",
   "description"=>"Eine Person, die kürzlich Ingenieurin wurde und als Grundschullehrerin oder Mittelsmann arbeitete. Viel Spaß beim Lösen des Rätsels.#RUNTEQ",
   "url"=>"https://t.co/zeP2KN6GMM",
    ...
  }
}

[12] pry(#<OauthsController>)> access_token
=> #<OAuth::AccessToken:0x00007f2fc41402d0
 @consumer=
  #<OAuth::Consumer:0x00007f2fc405c008
   @debug_output=nil,
   @http=#<Net::HTTP api.twitter.com:443 open=false>,
   @http_method=:post,
   @key="aaaaaaaaaaaaaaaaa",
   @options=
    {:signature_method=>"HMAC-SHA1",
     :request_token_path=>"/oauth/request_token",
     :authorize_path=>"/oauth/authenticate",
     :access_token_path=>"/oauth/access_token",
     :proxy=>nil,
     :scheme=>:header,
    ...

③ Speichern Sie jede zugehörige Authentifizierung. Authentifizierungsinstanzen, die von "@ user.build_authentication", "@ user.authentications.build" usw. erstellt wurden, werden beim Speichern zusammen mit dem Benutzer gespeichert.

Modelländerung

Es ist gefährlich, access_token und access_token_secret so zu speichern, wie sie sich in der Datenbank befinden. Speichern Sie sie daher verschlüsselt.

app/models/authentication.rb


class Authentication < ApplicationRecord
  before_save :encrypt_access_token
  belongs_to :user

  validates :uid, presence: true
  validates :provider, presence: true

  def encrypt_access_token
    key_len = ActiveSupport::MessageEncryptor.key_len
    secret = Rails.application.key_generator.generate_key('salt', key_len)
    crypt = ActiveSupport::MessageEncryptor.new(secret)
    self.access_token = crypt.encrypt_and_sign(access_token)
    self.access_token_secret = crypt.encrypt_and_sign(access_token_secret)
  end
end

Schneiden Sie Twitter :: REST :: Client in eine Serviceklasse aus

Schneiden Sie die Logik für den Twitter-Client für die Serviceklasse aus. Wenn der Benutzer in das Argument einbezogen ist, verwenden Sie das access_token usw. des Benutzers. Wenn der Benutzer nicht übergeben wird, verwenden Sie das standardmäßige access_token usw.

app/services/twitter_api_client.rb


require 'twitter'

class ApiClient
  def self.call(user = nil)
    new.call(user)
  end

  def call(user)
    @user = user
    @client ||= begin
      Twitter::REST::Client.new do |config|
        config.consumer_key        = Rails.application.credentials.twitter[:key]
        config.consumer_secret     = Rails.application.credentials.twitter[:secret_key]
        config.access_token        = access_token
        config.access_token_secret = access_token_secret
        config.dev_environment     = 'premium'
      end
    end
  end

  private

  attr_reader :user

  def access_token
    @access_token ||= user ? crypt.decrypt_and_verify(user.authentication.access_token)
                           : Rails.application.credentials.twitter[:access_token]
  end

  def access_token_secret
    @access_token_secret ||= user ? crypt.decrypt_and_verify(user.authentication.access_token_secret)
                                  : Rails.application.credentials.twitter[:access_token_secret]
  end

  def crypt
    key_len = ActiveSupport::MessageEncryptor.key_len
    secret = Rails.application.key_generator.generate_key('salt', key_len)
    ActiveSupport::MessageEncryptor.new(secret)
  end
end

Sie können eine Client-Instanz mit "TwitterApiClient.call (Benutzer)" aufrufen. Verwenden Sie beim Schreiben als Code etwas wie "TwitterApiClient.call (Benutzer) .update (" Ich twittere mit @gem! ")".

Recommended Posts

[Rails] Erhalten Sie access_token zum Zeitpunkt der Twitter-Authentifizierung mit Sorcery und speichern Sie es in der Datenbank
Holen Sie sich Youtube-Videoinformationen mit Retrofit und behalten Sie sie in der Android-App.
Umweltbauweise und Fehlerbehebung zum Zeitpunkt der gemeinsamen Entwicklung (Schienen, Docker und Github)
[JavaScript] Axios (Ajax) kann den Antworttext zum Zeitpunkt eines Fehlers nicht abrufen
Erstellen Sie eine Bulletin-Board-API mit Autorisierung in Rails 6 # 12 Assoziation von Benutzer und Beitrag
Stellen Sie die Sensorinformationen von Raspberry Pi in Java grafisch dar und überprüfen Sie sie mit einem Webbrowser
Generieren Sie mit TableGenerator of Hibernate (JPA) eine Seriennummer und speichern Sie diese in der ID von String.
[Rails] So erhalten Sie die URL der Übergangsquelle und leiten sie um
Überprüfen Sie das aktuelle Datum und die Uhrzeit beim Analysieren mit Javas SimpleDateFormat
[Java] Ordnen Sie die Daten des vergangenen Montags und Sonntags der Reihe nach an
Rufen Sie das aktuelle Datum und die aktuelle Uhrzeit ab, indem Sie die Zeitzone in Thymeleaf angeben
[Rails] Über Uglifier :: Fehler: Unerwartetes Token: Zum Zeitpunkt der Bereitstellung
[Schienen] Startzeit und Endzeit speichern
Welche Klasse sollte verwendet werden, um Datum und Uhrzeit in der Rails-App abzurufen (Time, DateTime, TimeWithZone)?
[Java] Geben Sie das Ergebnis von ffprobe -show_streams in JSON aus und ordnen Sie es einem Objekt in Jackson zu
[Rails] Unterschied im Verhalten zwischen Delegat und has_many-through bei Eins-zu-Eins-zu-Viele
Zeichnen Sie mit MPAndroidChart gleichzeitig Balkendiagramm und Liniendiagramm
Zum Zeitpunkt der Neuregistrierung E-Mail-Sendefunktion mit Action Mailer
Verwenden Sie Docker-Compose, um Ihre Lieblings-IP im Host-Netzwerk anzugeben und zu starten.
[Rails 6] Registrieren und Anmelden mit Devise + SNS-Authentifizierung (mehrere Links zulässig)
[Rails] So erhalten Sie die aktuell mit devise angemeldeten Benutzerinformationen
So implementieren Sie die E-Mail-Authentifizierungsfunktion zum Zeitpunkt der Benutzerregistrierung
[Rails] So lösen Sie die Zeitverzögerung von created_at nach der Speichermethode
Ändern Sie das Speicherziel des Bildes in der Rails-App in S3. Teil 2
Holen Sie sich das Ergebnis von POST in Java
Die Identität der Schienenparameter [: id]
Ich habe die Daten der Reise (Tagebuchanwendung) in Java erhalten und versucht, sie # 001 zu visualisieren
Java: Laden Sie die Datei herunter und speichern Sie sie an dem im Dialogfeld [Use HttpClient] ausgewählten Speicherort.
So erhalten Sie die ID eines Benutzers, der sich in Swift bei Firebase authentifiziert hat
[Rails] Ruft den Pfadnamen der URL vor dem Übergang ab und ändert das Linkziel