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. 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.
Ruby 2.6.6 Rails 5.2.4.3 Sorcery 0.15.0
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 ").
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
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.
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 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