【Rails】Facebookでユーザー認証する

## はじめに

FacebookでOmniAuthでユーザー認証しましょう。かっこいいからです。
似たような記事はたくさんありますが、Facebookの仕様変更などで、記事単体では実装が完了しないものばかりだったので改めて書くことにしました。


## まずdeviseのみで認証機能を実装

以下のサイトを参考につくります。
[【Railsのアプリ開発】初心者でもわかる！deviseでログイン機能を実装する使い方](https://freesworder.net/rails-devise/)

暇があれば上の内容も自分でしっかり解説して書きたいところですが、「暇があれば」などと言うのは大体やらない兆しです。期待しないでください。


### ユーザー一覧ページの作成

認証ページだけ作っても寂しいので、ユーザー一覧ページを作っておくと良いでしょう。

```
$ rails g controller users
```

これで作成されるファイルのうち、コントローラーとビューを以下のように変更して、ユーザー一覧ページを作成します。


```app/controllers/users_controller.rb
class UsersController < ApplicationController
  before_action :authenticate_user!
  def index
    @users = User.all
  end
end
```

```erb:app/views/users/index.html.erb
<% @users.each do |u| %>
  <div class="user_field">
    <%= link_to u.email, destroy_user_session_path, method: :delete %>
  </div>
<% end %>
```

一覧表示されたユーザーのメールアドレスをクリックするとサインアウトするようにしました。

最後に、このusers#indexアクションへのルーティングを設定しておきます。

```config/routes.rb
Rails.application.routes.draw do
  # 省略

  resources :users, only: [:index]
  root "users#index"
end
```

サインイン後にはルートパスにリダイレクトされるので、簡単にサインインできたかどうかの確認ができるように、"users#index"をルートパスに設定しました。
Facebookでのサインインに成功すれば、ユーザー一覧のページに遷移し、そこに自分がFacebookに登録したメールアドレスが表示されるはずです。


## omniauthを実装

再び以下のサイトを参考に。
[【開発メモ】RailsアプリでFacebookログインの認証機能を実装させる方法](https://freesworder.net/rails-facebook/)

暇があれば。


## Facebookの変更に対応

2019/2/15時点で、これだけではまだ足りません。

Facebook側の仕様変更で、以下が必須になりました。

- アプリケーションにhttpsでアクセスするように設定する
- プライバシーポリシーを載せたURLを指定する

順にやっていきます。


### アプリケーションにhttpsでアクセスできるように設定する

httpsでアクセスできるようにするには、アプリケーションサーバーがSSL証明書というものを持っていないといけません。SSL証明書にはグレードがあり、グレードの高いものほどサイトの安全性を保証できるのですが、それらは発行するのに認証局にたくさんお金を払わなければなりません。
しかしグレードの低いもので良ければ、自分で作成することができます。自分で作成といってもよくわからないので、SSL証明書の作成は**mkcert**を使って楽にやってしまいましょう。

また、RailsのアプリケーションサーバーとしてPumaを使えば、SSL証明書に関するなんやかんやをいい感じにやってくれます。
PumaはRails5では標準のアプリケーションサーバーなので、これに関しては特にややこしいことはありませんが、何かこだわりや制約があって他のアプリケーションサーバーを使う場合はブラウザバックです。


#### mkcertでSSL証明書を作成

公式GitHub: [FiloSottile/mkcert](https://github.com/FiloSottile/mkcert)

READMEを読んで、mkcertをインストールします。
僕のパソコンはmacなので、Homebrewを使います。

```
$ brew install mkcert
$ mkcert -install
```

自分のRailsアプリケーションの適当な場所にSSL証明書を置くディレクトリを作り、SSL証明書を作成します。

```
$ mkdir config/certs && cd config/certs
$ mkcert localhost
```

これで、`config/certs`ディレクトリ内に`localhost.pem` と `localhost-key.pem`という名前のSSL証明書ができます。
以下のように配置されていればOKです。

![スクリーンショット 2019-02-15 22.12.19.png](https://qiita-image-store.s3.amazonaws.com/0/222511/c2b8b419-4ee0-f5af-4fe3-e31c95c171ab.png)



#### .gitignoreでSSL証明書を無視

SSL証明書はgitで管理したくないので、.gitignoreに追記します。

```.gitignore
（省略）

/config/certs/*
```


#### pumaの設定ファイルでSSL証明書を指定する

`config/puma.rb`の12行目くらいに、httpでのpumaのサーバーを3000番のポートで起動するという設定の一行があります（`port        ENV.fetch("PORT") { 3000 }`）。
httpsでアクセスできるようにしたい今、これはもはや必要ないのでコメントアウトし、以下のように3000番の座を乗っ取りましょう。

```config/puma.rb
（省略）

# Specifies the `port` that Puma will listen on to receive requests; default is 3000.
#
# port        ENV.fetch("PORT") { 3000 }

ssl_bind "0.0.0.0", "3000", {
  cert: "config/certs/localhost.pem",
  key:  "config/certs/localhost-key.pem"
}
```


#### アクセスしてみる

あとはいつもどおりサーバーを立ち上げて`https://localhost:3000`にアクセスするだけです（httpではなくhttpsです！）。

```
$ rails server
```


### プライバシーポリシーを載せたURLを指定する

プライバシーポリシーとは、収集した情報をこれこれこういう目的で使いますよという旨が書かれた文書のことです。とりあえず開発時にはアクセスできるサイトであればなんでもよいです。アプリケーションを公開する段階になったら、忘れずに自分のアプリケーション内にプライバシーポリシーを載せたページを作り、それを指定しましょう。

facebookの開発者用管理ページに以下のようにURLを設定しておきます。

![スクリーンショット 2019-02-15 21.08.24.png](https://qiita-image-store.s3.amazonaws.com/0/222511/abbe1b3e-5b01-dd0c-d01c-cc228e433e13.png)

プライバシーポリシーのURLの設定は以上です！簡単！


## 確認

`https://localhost:3000`にアクセスすると、サインインのページに遷移し、そこに「Sign in with Facebook」というリンクが表示されているはずです。これをクリックするとFacebookの認証画面が現れて…。自分のメールアドレスが表示されたでしょうか？

できたはずです。きっと…。


## [+α] deviseで使われるビューファイルを確認する

deviseで作成される諸々のユーザー認証のページは、そのままでは見ることもできません。
しかし以下の設定とコマンドで、ユーザー認証まわりのビューファイルを確認し、カスタマイズすることができるようになります。

`config/initializers/devise.rb`の238行目を以下のように書き換えます。

```config/initializers/devise.rb
config.scoped_views = true
```

`config/initializers`ディレクトリの中に入っているファイルを変更したので、もしサーバーを立ち上げていたらサーバーを再起動してください。このディレクトリの中のファイルはサーバー立ち上げ時にだけ読み込まれるからです。

続いて、ビューファイルを作成します。

```
$ rails g devise:views users
```

こうしてできたビューファイルのうち、`app/views/users/shared/_links.html.erb`を見てみると、下の方に以下のような記述があります。これが `Sign in with Facebook`などと表示してくれる部分です。

```erb:app/views/users/shared/_links.html.erb
<%- if devise_mapping.omniauthable? %>
  <%- resource_class.omniauth_providers.each do |provider| %>
    <%= link_to "Sign in with #{OmniAuth::Utils.camelize(provider)}", omniauth_authorize_path(resource_name, provider) %><br />
  <% end %>
<% end %>
```

deviseで作成したモデルにomniauthableというオプションがついていれば、この部分が表示され、サインインボタンが表示されるようになっています。今回はデザインまではいじりませんが、かっこいいユーザー認証ページを作成したければここを変えればいいということを覚えておいてください。