LoginSignup
8
4

More than 5 years have passed since last update.

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

Last updated at Posted at 2018-06-14

はじめに

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

8
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
8
4