remix-authを使ったログイン機能の実装
はじめに
この記事では、RemixのWebアプリケーションのログイン機能を実装するにあたり、remix-auth, remix-auth-formを使った実装について、説明します。
今回のソースコード
今回紹介するソースコードは、以下のGihtubのリポジトリで公開しています
また、記事での説明のためにコードの内容を一部修正しているため、リポジトリのコードと異なる点があることはご了承ください。
今回の実装環境
今回の実装にあたり利用したライブラリのバージョン等の環境は通りです。
- Node.js:v22.13.0
- @remix-run/node: 2.15.2
- @remix-run/react: 2.15.2
- @remix-run/serve: 2.15.2
- remix-auth: 4.1.0
- remix-auth-form: 3.0.0
ログイン機能の実装
ライブラリのインストール
ログイン機能の実装については、以下の公式ドキュメントを参考に実装しています。
まず、必要なライブラリのインストールを行います。
npm install remix-auth remix-auth-form
ログイン認証ロジックの実装
次に、「ログインの認証ロジック」を行うコードを実装します。 app/services/auth.server.ts
に対して、以下の様なコードを実装します。
// app/services/auth.server.ts
import { Authenticator } from 'remix-auth';
import { FormStrategy } from 'remix-auth-form';
// ログインユーザーの型定義
type User = {
id: number;
email: string;
displayName: string;
}
// ログイン認証処理クラス
export const authenticator = new Authenticator<User>();
// ログイン認証ロジックの定義
authenticator.use(
new FormStrategy(async ({ form }) => {
// フォームデータを取得
const email = form.get('email');
const password = form.get('password');
// Nullableチェック
if (!email || !password) {
throw Error('Both `email` and `password` must be required.');
}
// TODO: ここで対象のユーザー情報をDBから取得する処理を追加する
// 今回はサンプルのため、ユーザー情報を作成し必ず認証成功扱いとする
const user: User = {
id: 1,
email: email.toString(),
displayName: 'Test User1',
};
return user;
}),
'user-pass'
);
ここでは、ログインフォームから受け取ったフォームのリクエストデータである「メールアドレス(email)」と「パスワード(password)」から、対応するユーザー情報が存在するかチェックし、ログインの認証処理を行います。
もし有効なユーザー情報が存在する場合は、そのユーザー情報を返すことで、認証成功とします。一方で、ユーザー情報が存在しない場合は、例外を送出することで、認証エラーと扱います。
今回の実装では、本来はデータベース等を参照して正しいユーザー情報を取得すべきですが、サンプルのためユーザー情報を作成し、必ず認証成功扱いとします。
ログインセッション情報の管理ロジックの実装
次に、「ログインセッション情報を管理するロジック」を実装します。
今回はapp/services/session.server.ts
に対して、以下の様なコードを実装しました。
// app/services/session.server.ts
import { createCookieSessionStorage } from '@remix-run/node';
// SESSIONN_SECRET: 環境変数から取得する
const sessionSecret: string | undefined = process.env.SESSIONN_SECRET;
if (sessionSecret === undefined) {
throw new Error('`SESSION_SECRET` is required.');
}
// セッション管理ロジックの実装
// 今回はcookieによる管理で実装する
export const sessionStorage = createCookieSessionStorage({
cookie: {
name: 'remix_sample_session',
sameSite: 'lax',
path: '/',
httpOnly: true,
secrets: [sessionSecret],
secure: process.env.NODE_ENV === 'production',
maxAge: 60 * 60 * 24,
},
});
// セッション情報管理メソッド
export const { getSession, commitSession, destroySession } = sessionStorage;
ログインセッション情報を扱う上で、まず考慮すべき点はログインセッション情報の保存方法です。保存先としてブラウザの「Cookie」や、Redisなどの「Key-Value Store」や、「Database」などが挙げられます。Remixでは、様々なセッション情報の管理方法を提供していますので、詳しくは以下のドキュメントをご確認ください。
今回は一番実装が楽である「Cookie」での実装をしました。実装は「公式ドキュメント」を参考にしています。
また、設定項目であるsecrets
については、秘匿情報にあたるため、環境変数「SESSIONN_SECRET」として管理します。
以上の設定でのCookieに保存されるログインセッション情報は以下のようになります(ChromeのDevToolで確認)。
ログインフォーム画面の実装
最後に、ログインフォーム画面の実装について説明します。
import { Form } from '@remix-run/react';
import { ActionFunctionArgs, redirect } from '@remix-run/node';
import { authenticator } from '~/services/auth.server';
import { sessionStorage } from '~/services/session.server';
export default function LoginPage() {
return (
<Form action="/login" method="post">
<div>
<div>
<label htmlFor="email">メールアドレス</label>
<input
id="email"
name="email"
type="email"
placeholder="メールアドレスを入力してください"
/>
</div>
<div>
<label htmlFor="password">パスワード</label>
<input
id="password"
name="password"
type="password"
placeholder="パスワードを入力してください"
/>
</div>
</div>
<button type="submit">ログイン</button>
</Form>
);
}
export async function action({ request }: ActionFunctionArgs) {
// フォームから送信された情報を、ログイン認証処理で検証する
// 認証成功したらセッション情報として、ユーザー情報を取得する
const user = await authenticator.authenticate('user-pass', request);
// 実装したセッション管理メソッドで、ユーザー情報をセッション情報に設定する
const session = await sessionStorage.getSession(
request.headers.get('cookie')
);
session.set('user', user);
// レスポンスヘッダーのCookieに、先ほどのセッション情報を追記
// ログイン成功時の画面にリダイレクトする
throw redirect('/', {
headers: { 'Set-Cookie': await sessionStorage.commitSession(session) },
});
}
基本的には、ログイン認証処理で必要な情報を、フォームで送信できるように画面を実装します。
そして、フォームから送信された情報を、Remixのactionで受け取り、先ほど実装したログイン認証処理(app/services/auth.server.ts
)を行います。
ログインの認証処理に成功したら、先ほど実装したセッション管理メソッド(app/services/session.server.ts
)を使って、ログインユーザー情報を設定します。
最後に、レスポンスヘッダーのCookieに、ログイン情報セッションを追加し、ログイン成功時の画面にリダイレクトを行います。
終わりに
ここまで、remix-authを使ったログイン処理の実装についてとなります。
今回はログインが成功した場合の処理のみ実装していますが、実運用時は「入力値チェックのバリデーション」や、「ログイン認証エラー時のエラーハンドリング」などの機能が必要となります。次は、これらの機能についても、実装していきたいと思います。
Discussion