[RUBY] [Rails] Obtenez access_token au moment de l'authentification Twitter avec Sorcery et enregistrez-le dans la base de données

Quel est cet article

Lorsque vous utilisez l'API Twitter, vous pouvez utiliser votre propre (compte enregistré) access_token, access_token_secret ↓ pour obtenir des informations publiques sur les utilisateurs et des tweets. スクリーンショット 2020-10-05 8.23.35.png Cependant, vous devez utiliser un access_token et un access_token_secret uniques pour chaque utilisateur afin d'obtenir des informations sur les utilisateurs privés et pour permettre aux utilisateurs de tweeter via l'application. Dans cet article, j'écrirai une implémentation qui stocke et utilise access_token et access_token_secret des utilisateurs individuels dans la base de données.

On suppose que l'authentification Twitter a été implémentée dans [Rails] Sortery for Twitter authentication \ -Qiita.

【Mise en garde】 Cet article suppose qu'il n'y a aucun utilisateur au moment de la mise en œuvre. Si vous avez déjà un utilisateur (si vous ne pouvez pas réinitialiser les données utilisateur), l'accès_token de cet utilisateur sera nul, vous devrez donc ajouter un peu de branchement conditionnel ennuyeux.

environnement

Ruby 2.6.6 Rails 5.2.4.3 Sorcery 0.15.0

Modification des associations de modèles

Dans mon cas, j'ai supposé que l'authentification externe était uniquement pour Twitter, j'ai donc changé l'association en has_one comme suit.

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

Si vous travaillez avec d'autres services et que l'utilisateur has_many: authentifications, remplacez la description telle que ʻuser.authentication.hogepar ʻuser.authentications.find_by! (Fournisseur: 'twitter').

Créer un fichier de migration

Ajoutez les colonnes access_token et access_token_secret à la table d'authentification. Si vous utilisez un lien autre que Twitter, supprimez l'option facultative «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

Ajouter un contrôleur

Ce qui a changé par rapport à l'article précédent, c'est l'intérieur de la méthode create_user_from.

app/controllers/api/v1/oauths_controller.rb


class OauthsController < ApplicationController
  skip_before_action :require_login # applications_avant avec contrôleur_action :require_Si la connexion est définie

  def oauth
    login_at(auth_params[:provider])
  end

  def callback
    provider = auth_params[:provider]
    if auth_params[:denied].present?
      redirect_to root_path, notice: "J'ai annulé ma connexion"
      return
    end
    #Créez un nouvel utilisateur si vous ne pouvez pas vous connecter avec les informations d'identification envoyées (s'il n'y en a pas)
    create_user_from(provider) unless (@user = login_from(provider))
    redirect_to root_path, notice: "#{provider.titleize}Je me suis connecté avec"
  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_from est une méthode de sorcellerie. Mettez les données passées de provider (: twitter) à Sorcery en tant qu'attributs de l'instance User (@ user).

② Créez une instance d'authentification. Puisque @ user_hash, ʻaccess_tokencontient les données reçues de Twitter, utilisez-le. Au fait,build_authentication est une méthode de has_one, donc dans le cas de has_many, veuillez la définir sur ʻuser.authentications.build.

[11] pry(#<OauthsController>)> @user_hash
=> {:token=>"111111111111111111111",
 :user_info=>
  {"id"=>1048451188209770497,
   "id_str"=>"1048451188209770497",
   "name"=>"END",
   "screen_name"=>"aiandrox",
   "location"=>"Okayama tout le temps → Yamanashi un peu → Tokyo Imakoko",
   "description"=>"Une personne récemment devenue ingénieur, travaillant comme enseignant au primaire ou comme intermédiaire. Profitez de résoudre le mystère.#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,
    ...

③ Enregistrez chaque authentification associée. Les instances d'authentification créées par @ user.build_authentication, @ user.authentications.build, etc. sont enregistrées avec l'utilisateur lors de son enregistrement.

Modification du modèle

Il est dangereux de sauvegarder access_token et access_token_secret tels qu'ils sont dans la base de données, donc enregistrez-les cryptés.

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

Découpez Twitter :: REST :: Client dans une classe de service

Découpez la logique liée au client Twitter à la classe de service. Si l'utilisateur est inclus dans l'argument, utilisez le jeton d'accès de l'utilisateur, etc., et si l'utilisateur n'est pas passé, utilisez le jeton d'accès par défaut, etc.

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

Vous pouvez appeler une instance de Client avec TwitterApiClient.call (user). Lorsque vous écrivez sous forme de code, utilisez quelque chose comme TwitterApiClient.call (utilisateur) .update (" Je tweet avec @gem! ").

Recommended Posts

[Rails] Obtenez access_token au moment de l'authentification Twitter avec Sorcery et enregistrez-le dans la base de données
Obtenez des informations vidéo YouTube avec Retrofit et conservez-les dans l'application Android.
Méthode de construction de l'environnement et dépanneur au moment du développement conjoint (rails, docker et github)
[JavaScript] Axios (ajax) ne peut pas obtenir le corps de la réponse au moment d'une erreur
Créer une API de tableau d'affichage avec autorisation dans Rails 6 # 12 Association d'utilisateur et de publication
Représentez graphiquement les informations du capteur de Raspberry Pi en Java et vérifiez-les avec un navigateur Web
Générez un numéro de série avec TableGenerator of Hibernate (JPA) et stockez-le dans l'ID de String.
[Rails] Comment obtenir l'URL de la source de transition et la rediriger
Vérifiez la date et l'heure réelles lors de l'analyse avec SimpleDateFormat de Java
[Java] Obtenez les dates des derniers lundi et dimanche dans l'ordre
Obtenez la date et l'heure actuelles en spécifiant le fuseau horaire dans Thymeleaf
[Rails] About Uglifier :: Erreur: jeton inattendu: au moment du déploiement
[Rails] Enregistrer l'heure de début et l'heure de fin
Quelle classe doit être utilisée pour obtenir la date et l'heure dans l'application Rails (Time, DateTime, TimeWithZone)
[Java] Affiche le résultat de ffprobe -show_streams dans JSON et mappe-le à un objet dans Jackson
[Rails] Différence de comportement entre delegate et has_many-through dans le cas de one-to-one-to-many
Dessinez un graphique à barres et un graphique linéaire en même temps avec MPAndroidChart
Au moment de la nouvelle inscription, fonction d'envoi de courrier avec Action Mailer
Utilisez docker-compose pour spécifier votre adresse IP préférée sur le réseau hôte et lancez-la.
[Rails 6] Enregistrez-vous et connectez-vous avec l'authentification Devise + SNS (plusieurs liens sont autorisés)
[Rails] Comment obtenir les informations sur l'utilisateur actuellement connecté avec devise
Comment mettre en œuvre la fonction d'authentification du courrier au moment de l'inscription de l'utilisateur
[Rails] Comment résoudre le décalage temporel de created_at après la méthode de sauvegarde
Modifiez la destination d'enregistrement de l'image en S3 dans l'application Rails. Partie 2
Obtenez le résultat de POST en Java
L'identité des paramètres de rails [: id]
J'ai reçu les données du voyage (application agenda) en Java et j'ai essayé de les visualiser # 001
Java: Téléchargez le fichier et enregistrez-le à l'emplacement sélectionné dans la boîte de dialogue [Utiliser HttpClient]
Comment obtenir l'ID d'un utilisateur qui s'est authentifié avec Firebase dans Swift
[Rails] Obtenez le nom du chemin de l'URL avant la transition et modifiez la destination du lien