8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Railsでメール認証コードを送信&照合するAPIを実装してみた(Flutter連携・前編)

8
Posted at

はじめに

スマートフォンアプリなどでよくある
「メールアドレスを入力 → 認証コードを受信 → 入力して認証」
という仕組みを、自前のRails APIで構築する方法を紹介します。

今回はその前編として、バックエンド側での

  • 認証コードの生成
  • メール送信(ActionMailer)
  • コードの照合処理(バリデーション)
    までを実装していきます。

✅ 後編では、Flutterアプリ側でこのコードを入力する画面を
pinput パッケージで構築する方法を紹介予定です!


使用技術・環境

  • Ruby on Rails 7(APIモード)
  • ActionMailer(メール送信)
  • DB:MySQL or SQLite
  • メール送信:Mailtrap(開発) / AWS SES(本番)
  • Flutterアプリからリクエストを受ける構成を想定

認証フローの全体像


認証コードの発行処理

🔸 モデル作成

db/migrate/xxxx_create_email_verifications.rb
create_table :email_verifications do |t|  
  t.string :email, null: false  
  t.string :code, null: false  
  t.datetime :expires_at  
  t.datetime :verified_at  
  t.timestamps  
end  

🔸 コード生成ロジック

def generate_code  
  SecureRandom.random_number(1_000_000).to_s.rjust(6, '0')  
end  

コードリクエストAPI(メール送信)

app/controllers/auth_controller.rb
def request_code  
  email = params[:email]  
  code = generate_code  

  verification = EmailVerification.create!(  
    email: email,  
    code: code,  
    expires_at: 10.minutes.from_now  
  )  

  VerificationMailer.send_code(email, code).deliver_later  
  render json: { message: 'Verification code sent' }  
end  

メール送信処理(ActionMailer)

🔸 メーラー定義

app/mailers/verification_mailer.rb
class VerificationMailer < ApplicationMailer  
  def send_code(email, code)  
    @code = code  
    mail(to: email, subject: '認証コードのお知らせ')  
  end  
end  

🔸 テンプレート

app/views/verification_mailer/send_code.text.erb
以下の認証コードをアプリに入力してください:

<%= @code %>

5分以内にご入力ください。  

認証コード照合API

def verify_code  
  email = params[:email]  
  code = params[:code]  

  record = EmailVerification.find_by(email: email, code: code)  

  if record.nil?  
    render json: { error: 'コードが一致しません' }, status: :unauthorized  
  elsif record.expires_at < Time.current  
    render json: { error: '有効期限切れ' }, status: :unauthorized  
  elsif record.verified_at.present?  
    render json: { error: 'すでに認証済みです' }, status: :unprocessable_entity  
  else  
    record.update!(verified_at: Time.current)  
    render json: { message: '認証成功' }  
  end  
end  

セキュリティ対策の補足

  • コードの使い回し禁止:照合成功後は verified_at を更新
  • レート制限:IPやメール単位でスロットル処理(Rack::Attackなど)
  • メール送信制限:本番はSES等でSPF/DKIM/DMARCの設定を忘れずに
  • コード長・文字種:桁数や英数混合でブルートフォース対策

次回予告:Flutterアプリ側の実装

後編では pinput パッケージを使って、以下のUIをFlutterで実装予定です。

  • 6桁の認証コード入力フィールド
  • 自動フォーカス&入力完了検知
  • バリデーションエラーの表示
  • 成功時の画面遷移

まとめ

  • Rails APIだけでメール認証コードの実装は十分できる
  • Deviseを使わずにシンプルで柔軟な実装が可能
  • メール認証はセキュリティ要素とユーザビリティ両立が大事
  • 次回はアプリ側のUI/UX実装に進みます!

8
0
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
8
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?