概要
TwitterAPIを利用してすでにある認証機構に後付けでTwitterログインをつける際につまづいたことをまとめます。
自己流の解決方法なので最適ではない可能性が高いです。ご意見いただたら嬉しいです。
developerアカウントとか外部キーの取得に関しては記事がたくさんあるので省きます。
※Deviceなどの認証系のgemは使っていません。
記事を参考にして作ったモデルのメソッドはこんな感じ↓
def self.find_or_create_from_auth(auth)
provider = auth[:provider]
uid = auth[:uid]
name = auth[:info][:name]
image = auth[:info][:image]
self.find_or_create_by(provider: provider, uid: uid) do |user|
user.name = name
user.email = User.dummy_email(auth)
user.password = User.new_token
user.remote_image_url = image
end
end
既存のsessions#createと機能が被る
アクションとルーティングを分離することで解決した。
def twitter_create
@user = User.find_or_create_from_auth(request.env['omniauth.auth'])
log_in @user
flash[:success] = "Twitter認証に成功しました"
redirect_back_or root_url
end
get "/login", to: "sessions#new"
post "/login", to: "sessions#create"
get "/auth/:provider/callback", to: 'sessions#twitter_create'
delete "/logout", to: "sessions#destroy"
既存のUserテーブルはemailとpasswordが入力必須
ダミーEmailとパスワード用のトークンを発行することで代用した。
self.find_or_create_by(provider: provider, uid: uid) do |user|
user.name = name
user.email = User.dummy_email(auth)
user.password = User.new_token
user.remote_image_url = image
end
#API用ダミーemail生成
def self.dummy_email(auth)
"#{auth.uid}-#{auth.provider}@example.com"
end
#ランダムなトークンを生成
def new_token
SecureRandom.urlsafe_base64
end
その代わり、twitterログインするユーザーはtwitterAPI経由でしかログインできなくなる。
このデメリットを解決する手法は見つからなかった。もしくはそれが当たり前なのかも。
併せてusers/edit.html.erbでuser.providerに値が入っていたらEmailとパスワードを変更できる項目として表示しないようにした。
carrierwaveを利用している場合のimageカラムの取り扱い
carrierwaveを利用している場合アップローダーを経由する必要があるため
user.image = image #TwitterAPIから取得したプロフィール画像のパス
では通らず
user.remote_image_url = image #TwitterAPIから取得したプロフィール画像のパス
とする必要があった
まとめ
twitterAPIから情報を取得するまでは難しくないが、それを既存のアプリにどう組み込むかは頭を悩ませた。
同じように悩む方の救いになることを祈ります。