質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
Devise

Deviseとは、Ruby-on-Railsの認証機能を追加するプラグインです。

Ruby on Rails 6

Ruby on Rails 6は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

メール

メールは、コンピュータネットワークを利用し、 情報等を交換する手段のことです。

Q&A

0回答

2037閲覧

[Rails] devise_token_auth で、メール認証後にcurrent_userがnilになる

stimlocy

総合スコア11

Devise

Deviseとは、Ruby-on-Railsの認証機能を追加するプラグインです。

Ruby on Rails 6

Ruby on Rails 6は、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

Ruby on Rails

Ruby on Railsは、オープンソースのWebアプリケーションフレームワークです。「同じことを繰り返さない」というRailsの基本理念のもと、他のフレームワークより少ないコードで簡単に開発できるよう設計されています。

メール

メールは、コンピュータネットワークを利用し、 情報等を交換する手段のことです。

0グッド

1クリップ

投稿2021/12/27 09:28

環境

Rails 6.1.4.4
ruby 3.0.2
devise 4.8.1
devise_token_auth 1.2.0

問題

DeviseTokenAuthで、ユーザー登録後にメール認証のためのメッセージを送信し、ユーザーはメールから認証リンクを踏むことで、正式なユーザー登録となるフローです。

認証メッセージを送信し、認証リンクから認証を通すところまでは良いのですが、
ユーザー登録時に送信したconfirm_success_urlにリダイレクトされた時、current_user (current_api_user)がnilになってしまいます。

ユーザー認証が完了されたときの画面には、将来的にユーザーの関連情報を表示させるため、どのユーザーが認証されたのか特定する必要があります。
リダイレクト先のControllerでcurrent_userを有効にする方法はありませんか?

現状、ConfirmationsControllerで、redirect_toではなくrenderを使用すれば、そのままcurrent_userが利用できますが、confirm_success_urlの設定が生きません。

マイグレーション

ruby

1class DeviseCreateUsers < ActiveRecord::Migration[6.1] 2 def change 3 create_table :users do |t| 4 ## Database authenticatable 5 t.string :email, null: false, default: "" 6 t.string :encrypted_password, null: false, default: "" 7 8 ## Recoverable 9 t.string :reset_password_token 10 t.datetime :reset_password_sent_at 11 12 ## Rememberable 13 # t.datetime :remember_created_at 14 15 ## Trackable 16 t.integer :sign_in_count, default: 0, null: false 17 t.datetime :current_sign_in_at 18 t.datetime :last_sign_in_at 19 t.string :current_sign_in_ip 20 t.string :last_sign_in_ip 21 22 ## Confirmable 23 t.string :confirmation_token 24 t.datetime :confirmed_at 25 t.datetime :confirmation_sent_at 26 t.string :unconfirmed_email # Only if using reconfirmable 27 28 ## Lockable 29 # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts 30 # t.string :unlock_token # Only if unlock strategy is :email or :both 31 # t.datetime :locked_at 32 33 34 t.timestamps null: false 35 end 36 37 add_index :users, :email, unique: true 38 add_index :users, :reset_password_token, unique: true 39 add_index :users, :confirmation_token, unique: true 40 # add_index :users, :unlock_token, unique: true 41 end 42end

ruby

1class DeviseTokenAuthCreateUsers < ActiveRecord::Migration[6.1] 2 def up 3 ## Required 4 add_column :users, :provider, :string, null: false, default: "email" 5 add_column :users, :uid, :string, null: false, default: "" 6 7 ## Tokens 8 add_column :users, :tokens, :text 9 10 User.reset_column_information 11 User.find_each do |user| 12 user.uid = user.email 13 user.provider = 'email' 14 user.save! 15 end 16 17 add_index :users, [:uid, :provider], unique: true 18 end 19 20 21 def down 22 remove_columns :users, :provider, :uid, :tokens 23 end 24end

モデル

ruby

1class User < ApplicationRecord 2 # Include default devise modules. Others available are: 3 # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable 4 devise :database_authenticatable, :registerable, 5 :validatable, :confirmable, :trackable, :recoverable 6 include DeviseTokenAuth::Concerns::User 7end

ルーティング

ruby

1Rails.application.routes.draw do 2 # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html 3 4 # devise_for :users 5 resources :users, only: [] do 6 collection do 7 get 'wellcome', to: 'users#wellcome' 8 end 9 end 10 11 namespace :api, defaults: {format: 'json'} do 12 scope :v1 do 13 mount_devise_token_auth_for 'User', at: 'user_auth', 14 controllers: { 15 confirmations: "api/v1/devise_token_auth/users/confirmations" 16 } 17 end 18 end 19end

コントローラー

DeviseTokenAuth::ConfirmationsController

ruby

1# frozen_string_literal: true 2 3class Api::V1::DeviseTokenAuth::Users::ConfirmationsController < DeviseTokenAuth::ConfirmationsController 4 5 def show 6 @resource = resource_class.confirm_by_token(resource_params[:confirmation_token]) 7 if @resource.errors.empty? 8 yield @resource if block_given? 9 10 redirect_header_options = { account_confirmation_success: true } 11 12 if signed_in?(resource_name) 13 token = signed_in_resource.create_token 14 signed_in_resource.save! 15 16 redirect_headers = build_redirect_headers(token.token, token.client, redirect_header_options) 17 18 redirect_to_link = signed_in_resource.build_auth_url(redirect_url, redirect_headers) 19 else 20 redirect_to_link = DeviseTokenAuth::Url.generate(redirect_url, redirect_header_options) 21 end 22 23 binding.pry 24 current_api_user # => #<User email: "user@example.com", ~~~~~~~ > 25 26 redirect_to(redirect_to_link) # => UsersController#wellcome 27 # render template: 'users/wellcome', formats: [:html] 28 else 29 raise ActionController::RoutingError, 'Not Found' 30 end 31 end 32 33end

ruby

1class UsersController < Api::ApiController 2 # pryでの確認のため、一旦認証要求を外しています 3 before_action :authenticate_api_user!, except: [:wellcome] 4 5 # GET /users/wellcome?account_confirmation_success=true 6 def wellcome 7 binding.pry 8 current_api_user # => nil 9 @user = current_api_user 10 end 11 12end

ruby

1class Api::ApiController < ActionController::API 2 include DeviseTokenAuth::Concerns::SetUserByToken 3end

ruby

1class ApplicationController < ActionController::Base 2 ### for API 3 protect_from_forgery unless: -> { request.format.json? } 4end

View

ruby

1# app/views/users/wellcome.html.erb 2<h1>User (<%= current_api_user.email %>) Confirmed</h1>

余談

redirect_toされた後もsessionの方は生きているようで、
ConfirmationControllerでsign_in(@resource)を行い、UsersControllerでsession["warden.user.api_user.key"]から[[user_id], "暗号化されたパスワードの一部?"]が取り出せます。
ここのuser_idとパスワードから、認証されたユーザーを特定できそうです。
(この場合、before_action :authenticate_api_user!を使用しない前提となりますが…)

ただ、この方法は野暮ったい印象を受け安全でないような気がしますが、セキュリティ上で問題ないものでしょうか?
私はセキュリティの専門的な知識を持っていないため、もしお分かりであれば説明いただけると幸いです。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

MasaSakano

2021/12/30 10:44

質問は`current_user`がnilということですが、コードは `current_api_user`を参照していませんか? 関係がよくわかりません。 また、`authenticate_user!`ではなくて、`authenticate_api_user!` で間違いなかったですか?
stimlocy

2021/12/30 11:55

namespace :apiでroutesを設定しているので、Controller上ではcurrent_api_user/authenticate_api_user!で間違いないです。 Deviseの一般的な使用方法の慣例にならって質問上では言い換えており、本文上ではカッコ書きで補足していました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだ回答がついていません

会員登録して回答してみよう

アカウントをお持ちの方は

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問