Use Cases

实现Two-Factor Authentication (2FA):Claude Code 实战指南

了解implementing two-factor authentication (2fa):Claude Code 实战. 包含实用代码示例。

二要素认证を通过 Claude Code 实现

アカウントの安全を強化する二要素认证(2FA)は、現在のWeb应用に欠かせない機能です。借助 Claude Code,TOTPベースの2FA、QRコード显示、备份コードを含む完全な实现を构建可以。

TOTPの仕組み

TOTP(Time-based One-Time Password)は、共有シークレットと現在時刻から30秒ごとに6桁のコードを生成するアルゴリズムです。Google AuthenticatorやAuthyなどの应用で利用されています。

> TOTPベースの二要素认证实现。
> QRコード生成、有效化フロー、日志イン時の验证、
> 备份コード10個の生成も含めて。

シークレット生成とQRコード

// src/lib/two-factor.ts
import { authenticator } from 'otplib';
import QRCode from 'qrcode';
import crypto from 'crypto';
import { prisma } from './prisma';

export class TwoFactorService {
  // 2FA配置の開始(シークレットとQRコード生成)
  async setup(userId: string) {
    const secret = authenticator.generateSecret();
    const user = await prisma.user.findUnique({ where: { id: userId } });

    const otpauthUrl = authenticator.keyuri(
      user!.email,
      'MyApp',
      secret
    );

    const qrCodeDataUrl = await QRCode.toDataURL(otpauthUrl);

    // シークレットを一時保存(まだ有效化しない)
    await prisma.user.update({
      where: { id: userId },
      data: { twoFactorSecret: secret, twoFactorEnabled: false },
    });

    return { qrCodeDataUrl, secret };
  }

  // コードを验证して2FAを有效化
  async enable(userId: string, token: string) {
    const user = await prisma.user.findUnique({ where: { id: userId } });
    if (!user?.twoFactorSecret) throw new Error('2FAが設定されていません');

    const isValid = authenticator.verify({
      token,
      secret: user.twoFactorSecret,
    });

    if (!isValid) throw new Error('無効なコードです');

    // 备份コードを生成
    const backupCodes = this.generateBackupCodes();
    const hashedCodes = backupCodes.map((code) =>
      crypto.createHash('sha256').update(code).digest('hex')
    );

    await prisma.user.update({
      where: { id: userId },
      data: {
        twoFactorEnabled: true,
        backupCodes: hashedCodes,
      },
    });

    return { backupCodes }; // 用户に显示(一度だけ)
  }

  // 日志イン時のコード验证
  async verify(userId: string, token: string): Promise<boolean> {
    const user = await prisma.user.findUnique({ where: { id: userId } });
    if (!user?.twoFactorSecret) return false;

    // TOTPコードで验证
    const isValid = authenticator.verify({
      token,
      secret: user.twoFactorSecret,
    });

    if (isValid) return true;

    // 备份コードで验证
    const hashedToken = crypto.createHash('sha256').update(token).digest('hex');
    const codeIndex = user.backupCodes.indexOf(hashedToken);
    if (codeIndex !== -1) {
      // 使用済みの备份コードをDelete
      const updatedCodes = [...user.backupCodes];
      updatedCodes.splice(codeIndex, 1);
      await prisma.user.update({
        where: { id: userId },
        data: { backupCodes: updatedCodes },
      });
      return true;
    }

    return false;
  }

  private generateBackupCodes(count = 10): string[] {
    return Array.from({ length: count }, () =>
      crypto.randomBytes(4).toString('hex').toUpperCase()
    );
  }
}

2FA配置画面

// src/components/TwoFactorSetup.tsx
'use client';
import { useState } from 'react';

export function TwoFactorSetup() {
  const [step, setStep] = useState<'idle' | 'qr' | 'verify' | 'backup'>('idle');
  const [qrCode, setQrCode] = useState('');
  const [token, setToken] = useState('');
  const [backupCodes, setBackupCodes] = useState<string[]>([]);

  const startSetup = async () => {
    const res = await fetch('/api/user/2fa/setup', { method: 'POST' });
    const data = await res.json();
    setQrCode(data.qrCodeDataUrl);
    setStep('qr');
  };

  const verifyAndEnable = async () => {
    const res = await fetch('/api/user/2fa/enable', {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ token }),
    });
    const data = await res.json();
    setBackupCodes(data.backupCodes);
    setStep('backup');
  };

  if (step === 'idle') {
    return (
      <button onClick={startSetup} className="bg-blue-600 text-white px-6 py-2 rounded-lg">
        二要素認証を設定する
      </button>
    );
  }

  if (step === 'qr') {
    return (
      <div className="space-y-4">
        <p className="dark:text-gray-300">認証アプリでQRコードをスキャンしてください</p>
        <img src={qrCode} alt="QRコード" className="mx-auto" />
        <input
          value={token}
          onChange={(e) => setToken(e.target.value)}
          placeholder="6桁のコードを入力"
          className="w-full border rounded px-3 py-2"
          maxLength={6}
        />
        <button onClick={verifyAndEnable} className="bg-blue-600 text-white px-6 py-2 rounded-lg w-full">
          確認して有効化
        </button>
      </div>
    );
  }

  return (
    <div className="space-y-4">
      <h3 className="font-bold text-green-600">二要素認証が有効になりました</h3>
      <p className="text-sm text-gray-600 dark:text-gray-400">
        以下のバックアップコードを安全な場所に保存してください。各コードは一度だけ使えます。
      </p>
      <div className="grid grid-cols-2 gap-2 bg-gray-50 dark:bg-gray-800 p-4 rounded-lg font-mono text-sm">
        {backupCodes.map((code, i) => (
          <span key={i} className="dark:text-gray-300">{code}</span>
        ))}
      </div>
    </div>
  );
}

関連文章

认证全般相关内容请参阅认证機能の实现指南、密码関連は密码重置实现也可以参考。

TOTP的规范请参阅RFC 6238で定義されています。

#Claude Code #two-factor auth #2FA #TOTP #security