Edited at

[Facebookログイン]Railsでプロフィール画像を取得したい

More than 1 year has passed since last update.


はじめに

Railsで開発しているAPIアプリケーションでFacebookのプロフィール画像の取得をやってみます。


環境


  • Mac OSX

  • Rails 5.2

  • ruby 2.5.1

  • Facebook Graph API v3.0

RailsからGraph APIへのアクセスはkoalaを、FacebookのAPIキーなどの管理にはfigaroを使っています。


前提



  • FacebookDevelopに登録する

  • 新規アプリを作成しAppIDSecretKeyを取得する

  • API側はknockを使ってJWTトークンを返す


準備


アクセスキーの設定


config/application.yml

FB_APP_ID: '取得したAppID'

FB_SECRET_KEY: '取得したSecretKey'


処理の流れ


  1. アプリケーションにはFacebookのユーザーアクセストークンがPOSTされる

  2. トークンの有効性を検証する

  3. トークンからGraph APIにアクセスして必要なユーザー情報を取得する

  4. 取得したユーザー情報を保存する


実装

今回はcontrollerとserviceクラスで実装しました。

色々やり方があると思いますが、以下サンプルです。


app/controllers/facebook_controller.rb

class FacebookUserTokenController < ApplicationController

before_action :authenticate

def create
render json: auth_token, status: :created
end

private

def authenticate
unless entity.present?
raise Knock.not_found_exception_class
end
end

def auth_token
if entity.respond_to? :to_token_payload
Knock::AuthToken.new payload: entity.to_token_payload
else
Knock::AuthToken.new payload: { sub: entity.id }
end
end

def entity
@entity ||=
if FacebookService.valid_token?(auth_params[:access_token])
data = FacebookService.fetch_data(auth_params[:access_token])
User.find_or_create_by(uid: data['id'], provider: 'facebook') do |user|
user.nickname = data['name']
user.first_name = data['first_name']
user.last_name = data['last_name']
user.email = data['email']
user.image_url = data.dig('picture', 'data', 'url')
user.password = SecureRandom.urlsafe_base64
end
end
end

def auth_params
params.require(:auth).permit :access_token
end
end



app/services/facebook_service.rb

class FacebookService

def self.valid_token?(access_token)
status = false
begin
# We need to check if the access_token is valid for our FB APP. Source: https://developers.facebook.com/docs/facebook-login/manually-build-a-login-flow#checktoken
debug_token = Koala::Facebook::API.new(access_token).debug_token(app_access_token_info['access_token'])
status = true if debug_token['data']['is_valid']
ensure
return status
end
end

def self.fetch_data(access_token)
Koala::Facebook::API.new(access_token).get_object('me', fields: 'name,first_name,last_name,email,picture') if valid_token?(access_token)
end

def self.app_access_token_info
@app_access_token ||= Koala::Facebook::OAuth.new.get_app_access_token_info
end
end


controllerでServiceクラスを呼び出してトークンの検証やユーザー情報の取得をする処理を呼び出しています。

保存はfind_or_create_byを使っています。

プロフィール画像は

user.image_url = data.dig('picture', 'data', 'url')

で取得しています。

ここでhttps://hogehoge.jpgとかが返ってくればこの話は終わりでした


image_urlを見てると

puts user.image_url

# https://lookaside.facebook.com/platform/profilepic/?asid=xxxxxxxxxxxxxxxxx&height=50&width=50&ext=xxxxxxx&hash=xxxxxxxxxxx

普通に.jpgとかのURLかと思ったら違いました。

このリンクにアクセスするとブラウザだとプロフィール画像がダウンロードされました。

CDNからASIDに仕様変更したみたいです。

imgタグでも表示できましたが、このURLをこのまま保存するのもなんだかなあと・・・


画像をダウンロードして保存する

アプリケーション側で画像を保存するようにしてみます。


  1. 取得したURLからダウンロードして画像ファイルを作成する

  2. S3などにアップロードしてURLを保存する

このあたりはまた続き書きます。


参考

https://damelog.com/sns/facebook/urls-based-on-app-scoped-id-disabled/

https://stackoverflow.com/questions/2515931/how-can-i-download-a-file-from-a-url-and-save-it-in-rails