Web開発アーキテクチャの選択
現代のWeb開発には主に二つのアプローチがある。
- サーバーサイドレンダリング(SSR):サーバー側で動的にHTMLを生成し、クライアントに完全なページを送信する方式。初期表示が速く、検索エンジン最適化(SEO)に有利。
- フロントエンド・バックエンド分離:バックエンドはデータを提供するAPIのみを提供し、フロントエンドはAjax経由でデータ取得を行う方式。開発効率が高く、ユーザー体験も優れている。
各アーキテクチャの特徴
| 項目 | SSR | 分離型 |
|---|---|---|
| 初期表示速度 | 高速 | 遅い(データ取得後) |
| SEO対応 | 良好 | 制限あり(ただしSSR対応フレームワークで解決可能) |
| 開発効率 | 低 | 高 |
| サーバー負荷 | 高 | 低 |
両方の利点を組み合わせる戦略として、「トップページはサーバーサイドレンダリング、以降はクライアントサイドで動的処理」というハイブリッド方式が推奨される。
認証方式の選定
ユーザーの身元を確認する仕組みは、開発スタイルによって異なるベストプラクティスが存在する。
- SSR環境:Sessionベースの認証が適している。ブラウザのCookieとサーバー上のセッションストアを連携して状態管理。
- 分離型アーキテクチャ:JWT(JSON Web Token)を用いた無状態認証が主流。トークンをクライアントに保持させ、リクエスト毎に送信することで認証を維持。
Session認証の仕組み
HTTPプロトコルは「状態なし」(stateless)であるため、複数のリクエスト間で情報を保持できない。これを克服するために、CookieとSessionの組み合わせが使われる。
- クライアントがログインすると、サーバーはユーザー情報をメモリに保存し、一時的なセッションIDを
Set-Cookieヘッダーで返却。 - その後のリクエストでは、ブラウザが自動的に
Cookieを付加し、サーバーはそのセッションIDからユーザー情報を復元。
ExpressでのSession設定例
// セッションミドルウェアの導入
const session = require('express-session');
app.use(session({
secret: 'my_secure_secret_key',
resave: false,
saveUninitialized: true
}));
// ログイン処理
app.post('/login', (req, res) => {
const { username, password } = req.body;
if (username !== 'admin' || password !== '123456') {
return res.status(401).json({ error: 'Invalid credentials' });
}
req.session.user = { username };
req.session.authenticated = true;
res.json({ message: 'Login successful' });
});
// 認証済みリソースのアクセス
app.get('/profile', (req, res) => {
if (!req.session.authenticated) {
return res.status(401).json({ error: 'Unauthorized' });
}
res.json({ user: req.session.user });
});
// ログアウト
app.post('/logout', (req, res) => {
req.session.destroy(err => {
if (err) return res.status(500).json({ error: 'Logout failed' });
res.json({ message: 'Logged out successfully' });
});
});
JWT認証の仕組み
JWTは、サーバーに状態を保持せず、トークン自体にユーザー情報と署名を含むことで、クロスドメインやマイクロサービス環境でも利用可能な認証方式。
- トークンは
Header.Payload.Signatureの三部構成。 - 署名は
secretKeyを使って生成され、改ざんを検出可能。 - クライアントは
localStorageまたはsessionStorageに保存し、リクエストヘッダーのAuthorization: Bearer <token>形式で送信。
ExpressでのJWT実装
// 必要パッケージのインストール
// npm install jsonwebtoken express-jwt
const jwt = require('jsonwebtoken');
const { expressjwt: auth } = require('express-jwt');
const secretKey = 'my_jwt_secret_123';
// JWTの生成(ログイン時)
app.post('/login', (req, res) => {
const { username, password } = req.body;
if (username !== 'admin' || password !== '123456') {
return res.status(401).json({ error: 'Invalid credentials' });
}
const token = jwt.sign(
{ username },
secretKey,
{ expiresIn: '1h' }
);
res.json({ token: `Bearer ${token}` });
});
// 認証ミドルウェアの登録
app.use(auth({ secret: secretKey, algorithms: ['HS256'] }).unless({ path: [/^\/public/] }));
// 保護されたエンドポイント
app.get('/admin/data', (req, res) => {
// req.auth にユーザー情報が格納されている
res.json({ data: req.auth, message: 'Access granted' });
});
// エラーハンドリング
app.use((err, req, res, next) => {
if (err.name === 'UnauthorizedError') {
return res.status(401).json({ error: 'Invalid or expired token' });
}
res.status(500).json({ error: 'Internal server error' });
});
注意事項
- パスワードは
payloadに含めない。 - トークンの有効期限は短めに設定(例:1時間以内)。
- トークンの削除はクライアント側で行う(サーバーに保存しない)。