セッションベースの認証をGoFiberに追加
今回サーバにセッションベースのユーザ認証を追加した内容をまとめます.
セッションベースのユーザー認証
JSON Web Tokenベースのユーザー認証が好きでした.JWTを書くときにクライアントが格納するトークン値は常に不安定であるため、「secure storageforJWT」というキーワードを使って検索することが多く、次のような文章が発見されます.
GoFiber
Stateless JWT tokens cannot be invalidated or updated, and will introduce either size issues or security issues depending on where you store them. Stateful JWT tokens are functionally the same as session cookies, but without the battle-tested and well-reviewed implementations or client support.
Unless you work on a Reddit-scale application, there's no reason to be using JWT tokens as a session mechanism. Just use sessions.
この文章にかなりの共感があったため,新編のサービスはセッションに基づいてユーザ認証を行うことにした.
セッション・ベースのユーザー認証とは、ユーザーの「セッション」をサーバ上のデータベースに格納し、クライアントはそのセッションを見つけることができるセッション・キーのみを格納します.クライアントがセッションキーを使用してAPIを呼び出すと、サーバはセッションキーを使用してセッションデータベースにアクセスし、セッションが存在するかどうか、およびそのユーザが誰であるかを決定します.通常、「セッション」は、ユーザIDのサイズを記憶する.
セッションはサーバ側で保存および管理されるため、ユーザーがサーバ上でログイン/ログアウトを決定したり、セッションキーが漏洩または不正に漏洩した場合、すぐにサーバ上でセッションを無効にすることができるという利点があります.その欠点は、ユーザセッションを管理するために中央データベースが必要であり、多くのユーザが同時に接続するサービス(上記の例ではReddit)と、セッションを管理するデータベースのスケールの問題である.したがって,バックエンド構造が分散したマイクロサービスアーキテクチャなどの面では使いにくい.
セッション・ベースのユーザー認証コンポーネント
セッション・ベースのユーザー認証を実現するには、次の決定が必要です.データベース クライアントリポジトリ つまり、これはストレージの問題であり、通常は次のように選択されます.セッションを格納するために使用されるデータベース:通常、NoSQLまたはキー値データベースが使用されます.なぜなら、セッションには高速I/Oが必要であり、リレーションシップは必要ありません.通常、Redisなどのメモリベースの高性能NoSQLデータベースが使用されます. セッションキーを格納するクライアント・リポジトリ:通常、クッキーが使用されます.クライアントが GoFiberでのセッションベースのユーザー認証の構成
セッションベースのユーザ認証機能を実装する際に使用されるクッキーには、
2番目の
CORS設定
Cross-Origin Cookieを したがって、CORSに関連するGoFiberアプリケーションコードを以下のように変更します.
セッションを保存するためにデータベースを設定する必要があります.GoFiberはStop using JWT for sessionsを事前に定義した.私はすでにMongoDBを書いているので、まずMongoDBにセッションを追加しました.
セッション保存値の読み取りと書き込み
セッション・リポジトリとして、書き込み、読み取り、消去を行います.ユーザログイン時に書き込み、ユーザログアウト時に消去し、検証が必要なAPIで読み出す.
書き込み
フロントエンドでの使用
フロントエンドコードでは、
セッションベースのユーザー認証
JSON Web Tokenベースのユーザー認証が好きでした.JWTを書くときにクライアントが格納するトークン値は常に不安定であるため、「secure storageforJWT」というキーワードを使って検索することが多く、次のような文章が発見されます.
GoFiber
Stateless JWT tokens cannot be invalidated or updated, and will introduce either size issues or security issues depending on where you store them. Stateful JWT tokens are functionally the same as session cookies, but without the battle-tested and well-reviewed implementations or client support.
Unless you work on a Reddit-scale application, there's no reason to be using JWT tokens as a session mechanism. Just use sessions.
この文章にかなりの共感があったため,新編のサービスはセッションに基づいてユーザ認証を行うことにした.
セッション・ベースのユーザー認証とは、ユーザーの「セッション」をサーバ上のデータベースに格納し、クライアントはそのセッションを見つけることができるセッション・キーのみを格納します.クライアントがセッションキーを使用してAPIを呼び出すと、サーバはセッションキーを使用してセッションデータベースにアクセスし、セッションが存在するかどうか、およびそのユーザが誰であるかを決定します.通常、「セッション」は、ユーザIDのサイズを記憶する.
セッションはサーバ側で保存および管理されるため、ユーザーがサーバ上でログイン/ログアウトを決定したり、セッションキーが漏洩または不正に漏洩した場合、すぐにサーバ上でセッションを無効にすることができるという利点があります.その欠点は、ユーザセッションを管理するために中央データベースが必要であり、多くのユーザが同時に接続するサービス(上記の例ではReddit)と、セッションを管理するデータベースのスケールの問題である.したがって,バックエンド構造が分散したマイクロサービスアーキテクチャなどの面では使いにくい.
セッション・ベースのユーザー認証コンポーネント
セッション・ベースのユーザー認証を実現するには、次の決定が必要です.
fetch
などの関数を使用してAPIを呼び出すと、Originが同じである場合、Cookieは自動的にサーバに含めて送信されます.Cookieは小さくて軽いですが、その「自動」の特性のため、安全性の面で多くの弱点があり、数十年来様々な方法で改善されてきました.セッションキーの保存には、通常、httpOnly
およびsecure
タグが使用されます.セッションベースのユーザ認証機能を実装する際に使用されるクッキーには、
httpOnly
およびsecure
のオプションが含まれる.このうちhttpOnly
とは、CookieがクライアントのJavaScriptコードにアクセスできないことを意味する.たとえば、元のフロントエンドのJavaScriptコードから、document.cookie
APIで保存されているCookieを読み込み、書き込み、変更できますが、httpOnly
CookieはこのAPIからアクセスできません.ブラウザは、HTTP呼び出しに対してのみ自動的に含まれます.そのためJavaScriptを挿入することでCookieに対して攻撃をブロックするなど安全です.2番目の
secure
オプションは、SSL/TLS呼び出しのみに対応するCookieが含まれることを意味する.安全のための最も基本的な措置といえる.また、secure
オプションは、フロントエンドサーバとバックエンドサーバのホストが異なる場合、Cross-Origin構成にも必要です.CORS設定
Cross-Origin Cookieを
httpOnly
およびsecure
オプションとして使用するには、CORSにいくつかの制限があります.Access-Control-Allow-Credentials
はtrue
でなければなりません.Access-Control-Allow-Origin
および Access-Control-Allow-Headers
ワイルドカード(*
)の値は割り当てられません.どのOriginとHeadersが利用可能かを明確に定義する必要があります.app := fiber.New()
...
app.Use(cors.New(cors.Config{
// TODO: production 에서 수정
AllowOrigins: "https://localhost:3000",
AllowMethods: strings.Join([]string{
fiber.MethodGet,
fiber.MethodPost,
fiber.MethodDelete,
fiber.MethodPatch,
}, ","),
AllowCredentials: true,
}))
セッション・リポジトリの設定セッションを保存するためにデータベースを設定する必要があります.GoFiberはStop using JWT for sessionsを事前に定義した.私はすでにMongoDBを書いているので、まずMongoDBにセッションを追加しました.
import (
...
"github.com/gofiber/fiber/v2/middleware/session"
"github.com/gofiber/storage/mongodb"
...
)
// 전역변수로 선언해서 사용해도 좋다
var store *session.Store
func NewSessionStore() {
storage := mongodb.New(mongodb.Config{
ConnectionURI: "mongodb://...",
})
// Session 저장소 생성
store = session.New(session.Config{
Storage: storage,
...
})
}
ここには複数のオプションがありますが、デフォルトではオプションsecure
、httpOnly
、same-site
が調整されます.func NewSessionStore() {
...
// Session 저장소 생성
store = session.New(session.Config{
...
CookieSecure: true,
CookieHTTPOnly: true,
CookieSameSite: "None", // For cross-origin
})
}
では、Appの作成時にNewSessionStore
関数を呼び出します.func New() *fiber.App {
...
NewSessionStore()
...
app := fiber.New()
...
return app
}
GoFiberの公式サイトはMiddlewareセクションでセッションに関するコードを紹介していますが、厳密にはミドルウェアではありません.データベース設定に近い.データベース設定コードの近くで一緒に設定すればいいのですセッション保存値の読み取りと書き込み
セッション・リポジトリとして、書き込み、読み取り、消去を行います.ユーザログイン時に書き込み、ユーザログアウト時に消去し、検証が必要なAPIで読み出す.
書き込み
var store *session.Store
...
func SetSession(userID string, c *fiber.Ctx) error {
// Fiber Context 에 맞춰 세션 저장소를 불러온다.
sess, err := store.Get(c)
if err != nil {
return err
}
sess.Set("user", userID)
// set-cookie 헤더에 자동으로 세션키를 포함한다
if err := sess.Save(); err != nil {
return err
}
}
読み取りvar store *session.Store
...
func GetUserIDFromSession(userID string, c *fiber.Ctx) (string, error) {
// Fiber Context 에 맞춰 세션 저장소를 불러온다.
sess, err := store.Get(c)
if err != nil {
return err
}
raw := sess.Get("user")
if raw == nil {
return "", errors.New("user not logged in")
}
userID, ok := raw.(string)
if !ok {
return "", errors.New("malformed session")
}
return userID, nil
}
クリア
func RemoveAuthenticatedUserID(c *fiber.Ctx) error {
// Fiber Context 에 맞춰 세션 저장소를 불러온다.
sess, err := store.Get(c)
if err != nil {
return errors.WithStack(err)
}
if err := sess.Destroy(); err != nil {
return errors.WithStack(err)
}
return nil
}
sess.Destroy()
関数はクライアントCookieを削除することもあります.フロントエンドでの使用
フロントエンドコードでは、
fetch
関数を呼び出すときにcredentials: 'include'
値を追加することが重要です.await fetch('https://...', {
method: 'POST',
...
credentials: 'include'
})
Set-Cookie
Headerは応答の呼び出し、すなわちログインAPI呼び出しとして、credentials
を追加する必要がありますので、ご注意ください.Reference
この問題について(セッションベースの認証をGoFiberに追加), 我々は、より多くの情報をここで見つけました https://velog.io/@byron1st/GoFiber-에-세션-기반-인증-추가하기テキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol