はじめに
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に登録する
- 新規アプリを作成し
AppID
とSecretKey
を取得する - API側はknockを使ってJWTトークンを返す
準備
アクセスキーの設定
FB_APP_ID: '取得したAppID'
FB_SECRET_KEY: '取得したSecretKey'
処理の流れ
- アプリケーションにはFacebookのユーザーアクセストークンがPOSTされる
- トークンの有効性を検証する
- トークンからGraph APIにアクセスして必要なユーザー情報を取得する
- 取得したユーザー情報を保存する
実装
今回はcontrollerとserviceクラスで実装しました。
色々やり方があると思いますが、以下サンプルです。
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
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をこのまま保存するのもなんだかなあと・・・
画像をダウンロードして保存する
アプリケーション側で画像を保存するようにしてみます。
- 取得したURLからダウンロードして画像ファイルを作成する
- 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