0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Goで学ぶWebSocket:[JWT認証 & 負荷分散設計]

Posted at

はじめに

前回の記事では、WebSocketを活用した通知システム、Redisを使ったWebSocketサーバーの構築方法を解説しました。
今回はさらに発展させて、JWT認証を組み込んだWebSocket実装と 負荷分散を考慮した設計について解説します。

対象読者

  • WebSocketに認証を組み込みたい方
  • 負荷の高いWebSocketアプリを効率的にスケールアウトしたい方
  • セキュアなリアルタイム通信を実現したい方

目次

  1. JWT認証を組み込んだセキュアなWebSocketの実装
    • JWT認証とは?
    • GoでのJWT認証の実装
    • WebSocketへのJWT認証の適用
  2. 負荷分散を考慮したWebSocket設計
    • 負荷分散の仕組み
    • WebSocketをスケールアウトする方法
    • Redis & Nginxを使った負荷分散

1. JWT認証を組み込んだセキュアなWebSocketの実装

1.1 そもそもJWT認証とは?

JWT(JSON Web Token) は、Webアプリケーションで広く使われる認証方式です。

JWTの仕組み:

  1. ユーザーがログイン → サーバーが秘密鍵でJWTトークンを発行
  2. クライアントがJWTをリクエストヘッダーに追加
  3. サーバーがJWTを検証し、認証を通過した場合のみ接続を許可

JWT の例:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsImV4cCI6MTY3NTAwMDAwMH0.mFkjcYJwGm7SUk8BzL7L5bJxz5XL8yYpXFA0eH0H-lw

1.2 GoでのJWT認証の実装

まず、JWTライブラリをインストールします。

go get github.com/golang-jwt/jwt/v4

jwt.go

package main

import (
    "fmt"
    "time"
    "github.com/golang-jwt/jwt/v4"
)

var secretKey = []byte("supersecretkey")

type Claims struct {
    UserID int `json:"userId"`
    jwt.RegisteredClaims
}

func GenerateJWT(userID int) (string, error) {
    claims := Claims{
        UserID: userID,
        RegisteredClaims: jwt.RegisteredClaims{
            ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour)),
        },
    }
    token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
    return token.SignedString(secretKey)
}

func ValidateJWT(tokenStr string) (*Claims, error) {
    token, err := jwt.ParseWithClaims(tokenStr, &Claims{}, func(token *jwt.Token) (interface{}, error) {
        return secretKey, nil
    })
    if claims, ok := token.Claims.(*Claims); ok && token.Valid {
        return claims, nil
    }
    return nil, err
}

1.3 WebSocketへのJWT認証の適用

server.go

package main

import (
    "fmt"
    "net/http"
    "github.com/gorilla/websocket"
)

var upgrader = websocket.Upgrader{
    CheckOrigin: func(r *http.Request) bool { return true },
}

func handleWebSocket(w http.ResponseWriter, r *http.Request) {
    tokenStr := r.URL.Query().Get("token")
    claims, err := ValidateJWT(tokenStr)
    if err != nil {
        http.Error(w, "Unauthorized", http.StatusUnauthorized)
        return
    }
    fmt.Println("Authenticated user:", claims.UserID)

    conn, _ := upgrader.Upgrade(w, r, nil)
    defer conn.Close()

    for {
        _, msg, err := conn.ReadMessage()
        if err != nil {
            break
        }
        fmt.Printf("Received message: %s\n", msg)
    }
}
  • WebSocketのリクエストにJWTを含めることで認証されたユーザーのみ接続を許可する
  • ValidateJWT() でJWTの検証を行い、不正なトークンの場合は401 Unauthorizedを返す

2. 負荷分散を考慮したWebSocket設計

2.1 負荷分散の仕組み

WebSocketの負荷分散では、以下の2つの方式を採用します。

  1. Nginxを使ったWebSocket負荷分散
  2. Redisを使ったWebSocketのスケールアウト

2.2 WebSocketをスケールアウトする方法(Nginx + Redis)

NginxをリバースプロキシとしてWebSocket負荷分散を実装する

nginx.conf

http {
    upstream websocket_backend {
        server ws-server1:8080;
        server ws-server2:8080;
    }

    server {
        listen 80;
        location /ws {
            proxy_pass http://websocket_backend;
            proxy_http_version 1.1;
            proxy_set_header Upgrade $http_upgrade;
            proxy_set_header Connection "Upgrade";
        }
    }
}

2.3 Redisを使ったWebSocketセッション共有

複数のWebSocketサーバーがある場合、Redis Pub/Subを活用してメッセージを共有。

server_redis.go

rdb.Publish(ctx, "websocket_messages", message)

各WebSocketサーバーはRedisのメッセージを受信して全クライアントにブロードキャストされる。


まとめ

項目 説明
JWT認証 WebSocketで認証を行い、セキュアな通信を確立
Nginx負荷分散 WebSocketのトラフィックを複数のサーバーに分散
Redisセッション共有 複数サーバー間でメッセージを共有し、スケールアウト可能に

WebSocketは汎用性も高い仕組みで色々な用途があります!
参考になれば嬉しいです!

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?