LoginSignup
6
4

More than 5 years have passed since last update.

devise_token_authで複数認証するとアクセストークンが返ってこなかった

Last updated at Posted at 2019-01-16

Railsでdevise_token_authを使ってAPIの認証機能を作っているときに、User以外のモデル(例えばAdminなど)を追加したらレスポンスヘッダーにアクセストークン等がなくてハマった話。

環境

最初の認証モデルを作成

まず最初にactive_model_serializersをインストールして使える状態にした。
続いて、devise_token_authをインストールしてUserモデルを作成した。

$ rails g devise_token_auth:install User user
$ rails db:migrate
config/routes.rb
mount_devise_token_auth_for 'User', at: 'user'

だいだいこんな感じでUserモデルの認証機能ができるので、適当にUserを作成してアクセストークンを取得してみる。

User.create!(email: "hoge@hoge.com", password: "password")
$ curl -D - -X "POST" "http://localhost:3000/user/sign_in" -H "Content-Type: application/json" -d $'{"email": "hoge@hoge.com", "password": "password"}'

HTTP/1.1 200 OK
X-Frame-Options: xxxxxxxxxxxxxxxxxx
X-XSS-Protection: xxxxxxxxxxxxxxxxxx
X-Content-Type-Options: xxxxxxxxxxxxxxxxxx
X-Download-Options: xxxxxxxxxxxxxxxxxx
X-Permitted-Cross-Domain-Policies: xxxxxxxxxxxxxxxxxx
Referrer-Policy: xxxxxxxxxxxxxxxxxx
Content-Type: application/json; charset=utf-8
access-token: xxxxxxxxxxxxxxxxxx
token-type: xxxxxxxxxxxxxxxxxx
client: xxxxxxxxxxxxxxxxxxx
expiry: xxxxxxxx
uid: hoge@hoge.com
Vary: xxxxxxxxxxxxxxxxxx
ETag: xxxxxxxxxxxxxxxxxx
Cache-Control: xxxxxxxxxxxxxxxxxx
X-Request-Id: xxxxxxxxxxxxxxxxxx
X-Runtime: xxxxxxxxxxxxxxxxxx
Transfer-Encoding: xxxxxxxxxxxxxxxxxx

ログインが成功して作成したUserのaccess-tokentoken-typeclientexpiryuidをレスポンスヘッダーに含まれるので、以降はこれらをリクエストヘッダーに入れてアクセスする感じ。

続いて管理者用のモデルを追加してみる

devise_token_authは複数の認証モデルもサポートしているので、新しく管理者用のモデルとしてAdminモデルを追加みてみる。

$ rails g devise_token_auth:install Admin admin
$ rails db:migrate
config/routes.rb
mount_devise_token_auth_for 'User', at: 'user'
mount_devise_token_auth_for 'Admin', at: 'admin'

だいだいこんな感じでAdminモデルの認証機能ができるので、適当にAdminを作成してアクセストークンを取得してみる。

Admin.create!(email: "admin@hoge.com", password: "password")
$ curl -D - -X "POST" "http://localhost:3000/admin/sign_in" -H "Content-Type: application/json" -d $'{"email": "admin@hoge.com", "password": "password"}'

HTTP/1.1 200 OK
X-Frame-Options: xxxxxxxxxxxxxxxxxx
X-XSS-Protection: xxxxxxxxxxxxxxxxxx
X-Content-Type-Options: xxxxxxxxxxxxxxxxxx
X-Download-Options: xxxxxxxxxxxxxxxxxx
X-Permitted-Cross-Domain-Policies: xxxxxxxxxxxxxxxxxx
Referrer-Policy: xxxxxxxxxxxxxxxxxx
Content-Type: application/json; charset=utf-8
Vary: xxxxxxxxxxxxxxxxxx
ETag: xxxxxxxxxxxxxxxxxx
Cache-Control: xxxxxxxxxxxxxxxxxx
X-Request-Id: xxxxxxxxxxxxxxxxxx
X-Runtime: xxxxxxxxxxxxxxxxxx
Transfer-Encoding: xxxxxxxxxxxxxxxxxx

なんてこった、access-tokentoken-typeclientexpiryuidがない。
さっきのUserではあったのに、いったい何故・・・

解決策

stackoverflowに同じような事例があった。
どうもactive_model_serializerの影響っぽい。
ソースコードあんまり読んでないけど、ここで指定しているscopeがcurrent_userになってるから?

とりあえず回答にあるように、devise_token_authのSessionsControllerをoverrideしたらちゃんとアクセストークンが返ってきた。

app/controllers/admin/sessions_controller.rb
def render_create_success
  render json: {
    data: resource_data(resource_json: @resource.token_validation_response)
  }, scope: :current_admin
end

active_model_serializerが影響してるとは思わなかったのでハマってしまったが、もっと良い解決策がないかもう少し調査が必要かも・・・


追記

overrideするよりapplication_controllerに以下を追加する方法のほうが良さそう。

application_controller.rb
serialization_scope :view_context
6
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
6
4