見出し画像

【React】+【RailsAPI】 アプリ [3] ユーザー認証(devise/devise_token_auth/redux-token-auth)_前編

前回 に続き、フロントに React、バックエンドに Rails(APIモード)を使うアプリの、ユーザー認証周りについて書きたいと思います。

ユーザー管理や認証に devise、APIを利用するためのトークン認証に devise_token_auth、またそれを Redux で扱うための redux-token-auth を組み込みます。今回はモジュールの組み込み、設定と動作確認までを行います。

追記:後編を書きました

ユーザー管理/認証

devise
まず Rails 側のユーザー認証は、これまで sorcery を使っていましたが、
メール認証やパスワードリセットなどがデフォルトで組み込まれていて、よく使われている devise を使ってみました。

Gem のインストール

# Gemfile
gem 'devise'

# 必要であれば rails-i18n なども入れておく
gem 'devise-i18n'
gem 'rails-i18n'
$ bundle install --path vendor/bundle

Devise のインストール

$ bundle exec rails g devise:install

devise の設定ファイル devise.rb が生成されます。何のアトリビュートで認証するか、有効期限はどのくらいにするか、など様々設定があり必要に応じて変更出来ます。

1. Ensure you have defined default url options in your environments 〜〜

メール認証のための設定を促されるので対応します。
(prodcution.rb も利用するサービスに合わせて対応します)

# config/environments/development.rb
config.action_mailer.default_url_options = { host: 'localhost', port: 3001 }

ここではユーザーモデルの生成は行わず、↓の「User モデルの生成」で対応します。

devise_token_auth

Rails 側とトークン認証を行えるようにする Gem です。

Rails用のシンプルでマルチクライアントで安全なトークンベースの認証。SPAやモバイルアプリを構築していて、認証が必要な場合は、クッキーではなくトークンが必要です。このgemはリ​​クエストごとにトークンを更新し、短時間で期限切れにするので、アプリは安全です。また、それは各クライアント/デバイスのためのセッションを維持するので、あなたはあなたが望むだけ多くのセッションを持つことができます。

ドキュメントは こちら、実装は こちらのサイト などを参考にしました。

# Gemfile
gem 'devise_token_auth', github: 'lynndylanhurley/devise_token_auth'

Rails5.2 を使用する場合、下記「devise_token_authのエラー対応」の通り v1.1.0 の Gem から取得するとエラーになるので GitHub から最新を取得します。

User モデルの生成
モデルの名前、ルーティングパスの名前を指定してインストールします。

$ rails g devise_token_auth:install User auth

マイグレーションファイル、devise_token_auth 設定ファイル、モデルやルーティングの追加が行われます。

マイグレーション
必要に応じて user.rb を修正(Confirmable をコメントアウトするなど)してマイグレーションを実行します。

$ rails db:migrate


コントローラー、ルーティングの追加

$ rails g controller auth/registrations

DeviseTokenAuth モジュールを継承し、Strong Parameters を設定します。

# controllers/auth/registrations_controller.rb
module Auth
 class RegistrationsController < DeviseTokenAuth::RegistrationsController
   private
   def sign_up_params
     params.permit(:name, :email, :password, :password_confirmation)
   end
   def account_update_params
     params.permit(:name, :email)
   end
 end
end
# routes.rb
mount_devise_token_auth_for 'User', at: 'auth', controllers: {
 registrations: 'auth/registrations'
}

devise の設定を変更(config/initializers/devise_token_auth.rb)

# config/initializers/devise_token_auth.rb
config.change_headers_on_each_request = false

change_headers_on_each_request 

By default the access-token header will change after each request. The client is responsible for keeping track of the changing tokens
デフォルトでは、access-tokenヘッダーは各要求の後に変わります。 クライアントは、変化するトークンを追跡する責任があります。

この変数の設定はコメントアウトされており、デフォルトが true です。
自前の実装を省き簡易的な実装にする場合は false にして、token_lifespan を短く設定します(ログイン時にトークンをローカルストレージに保存し、期限切れ、もしくはログアウトまで使い回し続けます)。

ここではコメントアウト(true)のまま、後ほど自前で実装してみます。

ヘッダー名の名前対応付けの設定を有効にする

# config/initializers/devise_token_auth.rb

# 以下コメントを外して有効にする
config.headers_names = {:'access-token' => 'access-token',
                        :'client' => 'client',
                        :'expiry' => 'expiry',
                        :'uid' => 'uid',
                        :'token-type' => 'token-type' }


トークン認証のテスト

リクエストやレスポンスにトークンが含まれているか curl を使って確認します。

ユーザー登録リクエストをPOST
Rails サーバーを起動させます。

$ bundle exec rails s -p 3001

データ転送を行うコマンド curl を使って Rails サーバーへリクエストします。リクエスト先は '/auth'、-X で POST メソッドを指定し、-d で送信するパラメータを指定します。

$ curl -X POST http://localhost:3001/auth -d '[name]=test1&[email]=test1@gmail.com&[password]=hogehoge&[password_confirmation]=hogehoge'
{"status":"success","data":{"id":1,"provider":"email"

などデータが返って来れば成功ですが、エラーになる場合があります。

NoMethodError (undefined method `current_sign_in_at' for #<User:0x00007fcff18c8890>):

これはインストール(devise_token_auth:install)時に、ログイン追跡( :trackable)が有効な状態で user.rb が生成されますが、マイグレーションに関連するカラムが含まれていないためです。
:trackable をコメントアウトするなど対応します。

ログインのリクエストをPOST
リクエスト先は '/auth/sign_in' を指定します。
また、ログイン成功時にレスポンスのヘッダーで渡されるアクセストークンなどを表示するため、-v オプションを付加します。

$ curl -X POST -v http://localhost:3001/auth/sign_in -d '[email]=test1@gmail.com&[password]=hogehoge'
< Content-Type: application/json; charset=utf-8
< access-token: hogehoge
< token-type: Bearer
< client: fugafuga
< expiry: 1555633904
< uid: test1@gmail.com

とアクセストークンなどが返って来れば成功です。

ユーザー名変更のリクエストをPUT
リクエスト先は '/auth' を指定します。
上記で取得したアクセストークンなどを -H で付加してリクエストします。

curl -X PUT -v -H "access-token: hogehoge" -H "client: fugafuga" -H "uid: test1@gmail.com" http://localhost:3001/auth -d '[name]=newname'
{
 "name": "new-name"
}

と返って来れば成功です。

devise_token_authのエラー対応

ユーザー登録実行時にエラーになる。

ActiveRecord::AttributeMethods::Serialization::ColumnNotSerializableError
(Column `tokens` of type ActiveRecord::Type::Json does not support
`serialize` feature.
Usually it means that you are trying to use `serialize`
on a column that already implements serialization natively.

公式のissue によると Rails5.2 での不具合のようで、こちらのPR で修正されたようですが Gem は更新されていないため、GitHub から直接取得して対応しました。

# Gemfile
gem 'devise_token_auth', github: 'lynndylanhurley/devise_token_auth'

※既に devise_token_auth を取得していて、GitHub に上がっているバージョンと同一の場合、一度該当の bundle を削除して入れ直す必要があります。


この記事が気に入ったらサポートをしてみませんか?