はじめに
こんにちは!
新卒1年目の石川です。
記事をご覧いただきありがとうございます。
この記事では、ユーザー認証と認可の基本を説明します。
Webアプリケーション開発において、ユーザー認証(authentication)と認可(authorization)は非常に重要なセキュリティ機能なので整理してみました。
ぜひ最後までご覧ください!
今回は主に機能の流れを説明します。ロジックの主要部分がコントローラとヘルパーに集中しているため、モデルとビューについてこの記事では触れません。
目次
1. ユーザー認証 (Authentication)
ユーザー認証とは、ユーザーが誰であるかを確認することです。
今回は、ユーザー認証を「ユーザー登録」「ログイン/ログアウト」の2つの機能に分けて見ていきます!
ユーザー認証では、ユーザーがログインするために提供する情報(ユーザー名とパスワードなど)を使用する。
ユーザー登録
まずは、新規ユーザーを登録する機能を実装します。以下のコードは、ユーザー登録フォームを表示し、ユーザー情報をデータベースに保存するためのものです。ユーザー登録は、アプリケーションに新しいユーザーを追加するプロセスです。ユーザーは先ほども述べた通り、名前、メールアドレス、パスワードなどの情報を入力してアカウントを作成します。
class UsersController < ApplicationController
def new
@user = User.new
end
def create
@user = User.new(user_params)
if @user.save
reset_session
log_in @user
flash[:success] = "Welcome to the Sample App!"
redirect_to @user
else
render 'new', status: :unprocessable_entity
end
end
private
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end
『newアクション』
新しいユーザーオブジェクトを作成し、登録フォームを表示します。
『createアクション』
フォームデータを受け取り、新しいユーザーを保存します。保存に成功すれば、セッションをリセットしてログインし、プロフィールページにリダイレクトします。失敗した場合はフォームを再表示します。
『user_paramsメソッド』
ユーザーの name、email、password、password_confirmation パラメータを許可します。(private以降の記述なのでプライベートメソッドとして定義されています。これにより、外部からこのメソッドにアクセスすることができず、意図しない使い方を防ぎます。)
ログイン/ログアウト
次にユーザーがログイン・ログアウト機能を実装します。以下のコードは、セッションコントローラでログイン状態を管理する方法を示しています。ログインは、既存のユーザーがアプリケーションにアクセスできるようにするプロセスです。ログアウトは、ユーザーがアプリケーションから安全に退出するプロセスです。
class SessionsController < ApplicationController
def new
end
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
log_in user
redirect_to user
else
flash.now[:danger] = 'Invalid email/password combination'
render 'new', status: :unprocessable_entity
end
end
def destroy
log_out
redirect_to root_url, status: :see_other
end
end
『newアクション』
ログインフォームを表示します。
『createアクション』
フォームデータを受け取り、メールアドレスでユーザーを検索し、パスワードを認証します。認証に成功すればユーザーをログインさせてユーザープロフィールページにリダイレクトします。失敗した場合はエラーメッセージを表示してログインフォームを再表示します。
『destroyアクション』
現在のユーザーをログアウトさせ、ホームページにリダイレクトします。
2. ユーザー認可 (Authorization)
ユーザー認可は、ユーザーがどの操作を実行できるか、どのリソースにアクセスできるかを制御する仕組みです。これにより、ユーザーが許可された操作だけを実行できるようにし、セキュリティを確保します。
今回は、ユーザー認可を「アクセス制御」「フレンドリーフォワーディング」「フレンドリーフォワーディングのテスト」の3つの機能に分けて見ていきます!
アクセス制御
ユーザーが自分自身の情報のみを編集できるようにアクセス制御を実装します。ログインしていないユーザーが特定のアクションにアクセスできないようにします。
class UsersController < ApplicationController
before_action :logged_in_user, only: [:edit, :update]
before_action :correct_user, only: [:edit, :update]
def edit
@user = User.find(params[:id])
end
def update
@user = User.find(params[:id])
if @user.update(user_params)
flash[:success] = "Profile updated"
redirect_to @user
else
render 'edit', status: :unprocessable_entity
end
end
private
def logged_in_user
unless logged_in?
flash[:danger] = "Please log in."
redirect_to login_url, status: :see_other
end
end
def correct_user
@user = User.find(params[:id])
redirect_to(root_url, status: :see_other) unless current_user?(@user)
end
def user_params
params.require(:user).permit(:name, :email, :password, :password_confirmation)
end
end
『logged_in_userメソッド』
ログインしていないユーザーをログインページにリダイレクトします。
『correct_userメソッド』
現在のユーザーが正しいユーザーであるかを確認し、他のユーザーの編集を防ぎます。
『editアクション』
ユーザーのプロフィール編集フォームを表示します。
『updateアクション』
フォームから送信されたデータを使用してユーザーの情報を更新します。更新が成功すればプロフィールページにリダイレクトし、失敗すれば編集フォームを再表示します。
『user_paramsメソッド』
許可されたパラメータのみを受け取るためのストロングパラメータを定義します。
フレンドリーフォワーディング
フレンドリーフォワーディングは、ログイン後にユーザーを元の目的地にリダイレクトする機能です。これにより、ユーザーは希望したページにスムーズにアクセスできるようになります。
module SessionsHelper
def store_location
session[:forwarding_url] = request.original_url if request.get?
end
def redirect_back_or(default)
redirect_to(session[:forwarding_url] || default)
session.delete(:forwarding_url)
end
end
『store_locationメソッド』
アクセスしようとしたURLを保存します。
『redirect_back_orメソッド』
保存されたURLにリダイレクトし、保存されたURLがない場合はデフォルトのURLにリダイレクトします。
class SessionsController < ApplicationController
def create
user = User.find_by(email: params[:session][:email].downcase)
if user && user.authenticate(params[:session][:password])
forwarding_url = session[:forwarding_url]
reset_session
log_in user
redirect_to forwarding_url || user
else
flash.now[:danger] = 'Invalid email/password combination'
render 'new', status: :unprocessable_entity
end
end
end
『createアクション』
ユーザーのログインを処理します。ログインが成功した場合、forwarding_urlにリダイレクトし、保存されたURLがない場合はユーザーのプロフィールページにリダイレクトします。ログインに失敗した場合はエラーメッセージを表示し、ログインページを再表示します。
フレンドリーフォワーディングのテスト
フレンドリーフォワーディング機能が正しく動作するかどうかをテストします。
require "test_helper"
class UsersEditTest < ActionDispatch::IntegrationTest
def setup
@user = users(:michael)
end
test "successful edit with friendly forwarding" do
get edit_user_path(@user)
log_in_as(@user)
assert_redirected_to edit_user_url(@user)
name = "Foo Bar"
email = "foo@bar.com"
patch user_path(@user), params: { user: { name: name,
email: email,
password: "",
password_confirmation: "" } }
assert_not flash.empty?
assert_redirected_to @user
@user.reload
assert_equal name, @user.name
assert_equal email, @user.email
end
end
『setupメソッド』
テスト用のユーザーをセットアップします。
『テスト』
テストケース"successful edit with friendly forwarding"のフレンドリーフォワーディングをテストします。
3. 最後に
この記事ではユーザー認証と認可の重要性、そしてその実装方法について説明しました。ユーザー認証は、誰がアプリケーションにアクセスしているかを確認するプロセスであり、認可はそのユーザーがどの操作を行えるかを制御するプロセスです。これらの機能を適切に実装することで、アプリケーションのセキュリティを強化することができると思います!
この記事で具体的な実装方法がわかりやすくなれば幸いです。また、より安全で使いやすいアプリケーションを作り上げるために、この記事が少しでもお役に立てれば嬉しいです。
最後まで読んでいただきありがとうございました!