15
11

More than 3 years have passed since last update.

【Appleログイン】Sign in with Appleの実装手順(Ruby on Rails編)

Last updated at Posted at 2020-12-25

対象読者

  • Ruby on Railsで作成したWebアプリケーションにAppleログイン(Sign in wth Apple)を実装したい人

最近色々なサービスで頻繁に見かけるようになったAppleログインですが、その実装手順に関して意外と日本語の情報が少ないように感じたのでメモ書きとして残しておきたいと思います。

Dockerfileを書き始めるところから始めるので、ちゃんと手順に沿っていればとりあえず同じように再現できるはずです。

下準備

まず最初に環境構築のため各種フォルダ・ファイルを作成します。

ディレクトリを作成

$ mkdir sign-in-with-apple-sample
$ cd sign-in-with-apple-sample

各種ファイルを作成

$ touch Dockerfile
$ touch docker-compose.yml
$ touch Gemfile
$ touch Gemfile.lock
./Dockerfile
FROM ruby:2.6.6

RUN apt-get update -qq && apt-get install -y build-essential libpq-dev nodejs

ENV APP_PATH /myapp

RUN mkdir $APP_PATH
WORKDIR $APP_PATH

COPY Gemfile $APP_PATH/Gemfile
COPY Gemfile.lock $APP_PATH/Gemfile.lock
RUN bundle install

COPY . $APP_PATH
version: '3'
services:
  db:
    image: mysql:5.7
    environment:
      MYSQL_DATABASE: root
      MYSQL_ROOT_PASSWORD: password
    volumes:
      - mysql-data:/var/lib/mysql
    ports:
      - "3306:3306"

  web:
    tty: true
    stdin_open: true
    build: .
    command: bash -c "rm -f tmp/pids/server.pid && bundle exec rails s -p 3000 -b '0.0.0.0'"
    volumes:
      - .:/myapp
      - ./vendor/bundle:/myapp/vendor/bundle
    ports:
      - "3000:3000"
    links:
      - db

volumes:
  mysql-data:
./Gemfile
source 'https://rubygems.org'
gem 'rails', '~> 5.2.4'
./Gemfile.lock
# 空でOK

Railsプロジェクトを作成

$ docker-compose run web rails new . --force --no-deps -d mysql --skip-bundle
$ docker-compose build

database.ymlを書き換え

./config/database.yml
default: &default
  adapter: mysql2
  encoding: utf8
  pool: <%= ENV.fetch("RAILS_MAX_THREADS") { 5 } %>
  username: root
  password: password # デフォルトだと空欄になっているはずなので追記 
  host: db # デフォルトだと「localhost」になっているので書き換え

development:
  <<: *default
  database: myapp_development

コンテナを起動 & データベースを作成

$ docker-compose up -d
$ docker-compose run web rails db:create

localhost:3000へアクセス

スクリーンショット 2020-12-25 12.08.56.png

localhost:3000」へアクセスし、いつもの画面が表示されれれば成功です。

実装

準備ができたのでいよいよ実装に入ります。

各種gemの用意

./Gemfile
...

gem 'devise'
gem 'omniauth'
gem 'omniauth-apple'

今回使用する各種gemをインストールします。

$ docker-compose build

Gemfileを更新したので再度ビルド。

Deviseをインストール

$ docker-compose run web rails g devise:install

...

create  config/initializers/devise.rb
create  config/locales/devise.en.yml

Userモデルを作成

$ docker-compose run web rails g devise user

...

invoke  active_record
create  db/migrate/20201224203750_devise_create_users.rb
create  app/models/user.rb
invoke  test_unit
create  test/models/user_test.rb
create  test/fixtures/users.yml
insert  app/models/user.rb
route   devise_for :users

OmniAuth用のカラムを追加

$ docker-compose run web rails g migration AddColumnsToUsers uid:string provider:string
$ docker-compose run web rails db:migrate

OmniAuth用のモジュールとメソッドを追加

app/models/user.rb
class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable, :omniauthable, omniauth_providers: [:apple] # ←追加

  def self.from_omniauth(auth)
    where(provider: auth.provider, uid: auth.uid).first_or_create do |user|
      user.provider = auth.provider
      user.uid = auth.uid
      user.email = auth.info.email
      user.password = Devise.friendly_token[0, 20]
    end
  end
end

デフォルトの状態だと「omniauthable」「omniauth_providers」のモジュールが無いので追加し、「apple」を指定します。

各種コントローラーを作成

$ docker-compose run web rails g devise:controllers users

...

create  app/controllers/users/confirmations_controller.rb
create  app/controllers/users/passwords_controller.rb
create  app/controllers/users/registrations_controller.rb
create  app/controllers/users/sessions_controller.rb
create  app/controllers/users/unlocks_controller.rb
create  app/controllers/users/omniauth_callbacks_controller.rb

色々なコントローラーが一気に作成されますが、今回必要なのは「omniauth_callbacks_controller.rb」のみです。

./app/controllers/users/omniauth_callbacks_controller.rb
class Users::OmniauthCallbacksController < Devise::OmniauthCallbacksController
  skip_before_action :verify_authenticity_token, only: %i[apple]

  def apple
    @user = User.from_omniauth(request.env['omniauth.auth'])

    if @user.persisted?
      sign_in_and_redirect @user, event: :authentication
      set_flash_message(:notice, :success, kind: 'Apple') if is_navigational_format?
    else
      session['devise.apple_data'] = request.env['omniauth.auth'].except('extra')
      redirect_to new_user_registration_url
    end
  end
end

Rackミドルウェアを作成

参照記事: RailsとRack

./config/initializers/omniauth.rb
Rails.application.config.middleware.use OmniAuth::Builder do
  provider :apple, ENV['CLIENT_ID'], '',
           {
             scope: 'email name',
             team_id: ENV['TEAM_ID'],
             key_id: ENV['KEY_ID'],
             pem: ENV['APPLE_PRIATE_KEY'],
           }
end

config/initializers/配下に「omniauth.rb」というファイルを作成。

Sign in with Appleを実装するためには、Apple Developerに登録して

  • CLIENT_ID
  • TEAM_ID
  • KEY_ID
  • PRIVATE_KEY

といった4つの値を取得する必要があります。

参照記事:
Apple Developerのアカウント登録方法
Sign in with Apple を実装するために必要な証明書の作り方

この辺についてはすでに色々な記事が世の中に存在するので各自取得しておいてください。

Return URLsの設定

ここから一瞬だけApple Developer側の操作になります。

最後に、認証が許可された後のリダイレクト先を指定。

Apple Developerのダッシュボードから「Certifications, Identifers & Profiles」へ飛ぶ。

80911786-8d52f100-8d73-11ea-8bbd-39af246f5aee.png

「Identifers」タブを開き、右のプルダウンメニューから「Services IDs」を選択。

80911889-25e97100-8d74-11ea-8220-b0fe6ba46875.png

「Sign in with Apple」の右にある「configure」をクリックすると「Domains and Sub domains」「Return URLs」を登録する画面が出てくるので、それぞれ記述していきます。

スクリーンショット 2020-12-25 13.02.54_censored.jpg

Domains and Sub domains → 「http://」「.com」などを除外した部分
Return URLs → 後ろに「users/auth/apple/callback」を追加したもの

一つ注意点として、Sign in with Appleでは「localhost」が使用できません。

したがって、

localhost:3000
http://localhost:3000/users/auth/apple/callback

などと記述しても、不正な値として弾かれてしまいます。

そこで、「ngrok」などをいローカルサーバーに適当なドメインを割り当ててもらう方法で今回は試します。

参照記事:ngrokが便利すぎる

80912200-4e726a80-8d76-11ea-9ca3-a87b3deb3854.png

今回の場合はターミナルで

$ ngrok http 3000

と叩き、生成されたURLを先ほどのページに記述すればOKです。

ビューを作成

大体の準備は完了しましたが、ビューをまだ作成していないので適当に作ります。

$ docker-compose run web rails g controller home index
app/views/home/index.erb
<h1>Sign in with Apple</h1>

<% if user_signed_in? %>
  <%= link_to 'logout', destroy_user_session_path, method: :delete %>
  <h1>Hello、<%=  current_user.email %></h1>
<% else %>
  <%= link_to 'login', user_apple_omniauth_authorize_path %>
<% end %>

ルーティングを設定

ここまでに実装した機能が正常に動くようにルーティングを設定します。

./config/routes.rb
Rails.application.routes.draw do
  root to: 'home#index'
  devise_for :users, controllers: { omniauth_callbacks: 'users/omniauth_callbacks' }
end

動作確認

スクリーンショット 2020-12-25 11.31.35.png

ngrokで立ち上がったURLへアクセスし、↑のような画面になる事を確認。

80911472-8dea8800-8d71-11ea-8b4d-0fd215100e15_censored.jpg

「login」ボタンを押すとSign in with Appleのページへ飛ぶので、自身のAppleIDとパスワードをそれぞれ入力。

スクリーンショット 2020-12-25 11.42.46_censored.jpg

認証に成功すると、自身のメールアドレスが表示された画面に切り替わります。(「privaterelay.appleid.com」はSign in with Apple用に付与される独自のドメイン)

以上でSign in with Appleの実装は完了です。お疲れ様でした!

あとがき

Apple Developerへの登録だったり各種証明書の取得は面倒そうな印象を受けましたが、コードの実装自体は案外簡単だった気がします。

もしかするとUIが変わったりするかもしれませんが、基本的な考え自体は変わらないと思うので是非とも参考にしていただけると幸いです。

15
11
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
15
11