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

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

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

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

Ruby on Rails 6

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

Ruby on Rails

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

メール

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

受付中

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

stimlocy
stimlocy

総合スコア9

Devise

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

Ruby on Rails 6

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

Ruby on Rails

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

メール

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

0回答

0評価

1クリップ

863閲覧

投稿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

class DeviseCreateUsers < ActiveRecord::Migration[6.1] def change create_table :users do |t| ## Database authenticatable t.string :email, null: false, default: "" t.string :encrypted_password, null: false, default: "" ## Recoverable t.string :reset_password_token t.datetime :reset_password_sent_at ## Rememberable # t.datetime :remember_created_at ## Trackable t.integer :sign_in_count, default: 0, null: false t.datetime :current_sign_in_at t.datetime :last_sign_in_at t.string :current_sign_in_ip t.string :last_sign_in_ip ## Confirmable t.string :confirmation_token t.datetime :confirmed_at t.datetime :confirmation_sent_at t.string :unconfirmed_email # Only if using reconfirmable ## Lockable # t.integer :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts # t.string :unlock_token # Only if unlock strategy is :email or :both # t.datetime :locked_at t.timestamps null: false end add_index :users, :email, unique: true add_index :users, :reset_password_token, unique: true add_index :users, :confirmation_token, unique: true # add_index :users, :unlock_token, unique: true end end

ruby

class DeviseTokenAuthCreateUsers < ActiveRecord::Migration[6.1] def up ## Required add_column :users, :provider, :string, null: false, default: "email" add_column :users, :uid, :string, null: false, default: "" ## Tokens add_column :users, :tokens, :text User.reset_column_information User.find_each do |user| user.uid = user.email user.provider = 'email' user.save! end add_index :users, [:uid, :provider], unique: true end def down remove_columns :users, :provider, :uid, :tokens end end

モデル

ruby

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

ルーティング

ruby

Rails.application.routes.draw do # For details on the DSL available within this file, see https://guides.rubyonrails.org/routing.html # devise_for :users resources :users, only: [] do collection do get 'wellcome', to: 'users#wellcome' end end namespace :api, defaults: {format: 'json'} do scope :v1 do mount_devise_token_auth_for 'User', at: 'user_auth', controllers: { confirmations: "api/v1/devise_token_auth/users/confirmations" } end end end

コントローラー

DeviseTokenAuth::ConfirmationsController

ruby

# frozen_string_literal: true class Api::V1::DeviseTokenAuth::Users::ConfirmationsController < DeviseTokenAuth::ConfirmationsController def show @resource = resource_class.confirm_by_token(resource_params[:confirmation_token]) if @resource.errors.empty? yield @resource if block_given? redirect_header_options = { account_confirmation_success: true } if signed_in?(resource_name) token = signed_in_resource.create_token signed_in_resource.save! redirect_headers = build_redirect_headers(token.token, token.client, redirect_header_options) redirect_to_link = signed_in_resource.build_auth_url(redirect_url, redirect_headers) else redirect_to_link = DeviseTokenAuth::Url.generate(redirect_url, redirect_header_options) end binding.pry current_api_user # => #<User email: "user@example.com", ~~~~~~~ > redirect_to(redirect_to_link) # => UsersController#wellcome # render template: 'users/wellcome', formats: [:html] else raise ActionController::RoutingError, 'Not Found' end end end

ruby

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

ruby

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

ruby

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

View

ruby

# app/views/users/wellcome.html.erb <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!を使用しない前提となりますが…)

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

良い質問の評価を上げる

以下のような質問は評価を上げましょう

  • 質問内容が明確
  • 自分も答えを知りたい
  • 質問者以外のユーザにも役立つ

評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

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

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

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

teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

  • プログラミングに関係のない質問
  • やってほしいことだけを記載した丸投げの質問
  • 問題・課題が含まれていない質問
  • 意図的に内容が抹消された質問
  • 過去に投稿した質問と同じ内容の質問
  • 広告と受け取られるような投稿

評価を下げると、トップページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

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の一般的な使用方法の慣例にならって質問上では言い換えており、本文上ではカッコ書きで補足していました。

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

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

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

ただいまの回答率
87.20%

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

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

質問する

関連した質問

同じタグがついた質問を見る

Devise

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

Ruby on Rails 6

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

Ruby on Rails

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

メール

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