You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何将Supabase与Golang集成以实现Supabase的JWT令牌验证API?

Supabase与Golang集成:JWT令牌验证实现方案

一、前置准备

  • 从Supabase控制台获取三个核心值:
    • SUPABASE_JWT_SECRET:在Settings > API > JWT Secret中查看,用于验证令牌签名
    • 项目ID(可选):即Supabase URL中的前缀,用于验证令牌受众
  • 确保本地Go版本在1.18及以上

二、安装依赖

执行以下命令安装所需Go包:

go get github.com/golang-jwt/jwt/v5
go get github.com/joho/godotenv # 可选,用于加载环境变量

三、核心JWT验证逻辑

1. 环境变量加载(可选)

创建.env文件存储密钥:

SUPABASE_JWT_SECRET=你的JWT密钥

在代码中加载环境变量:

package main

import (
    "log"
    "os"

    "github.com/joho/godotenv"
)

func init() {
    if err := godotenv.Load(); err != nil {
        log.Println("未加载.env文件,将使用系统环境变量")
    }
}

2. 编写验证函数

自定义Claims结构体匹配Supabase JWT的字段,实现核心验证逻辑:

package main

import (
    "errors"
    "fmt"
    "strings"
    "time"

    "github.com/golang-jwt/jwt/v5"
)

var jwtSecret = []byte(os.Getenv("SUPABASE_JWT_SECRET"))

// SupabaseClaims 匹配Supabase颁发的JWT字段
type SupabaseClaims struct {
    Aud   string `json:"aud"`
    Exp   int64  `json:"exp"`
    Sub   string `json:"sub"`
    Email string `json:"email"`
    Role  string `json:"role"`
    jwt.RegisteredClaims
}

// ValidateSupabaseJWT 验证Supabase令牌有效性
func ValidateSupabaseJWT(tokenString string) (*SupabaseClaims, error) {
    // 移除Bearer前缀(如果存在)
    tokenString = strings.TrimPrefix(tokenString, "Bearer ")

    token, err := jwt.ParseWithClaims(tokenString, &SupabaseClaims{}, func(token *jwt.Token) (interface{}, error) {
        // 强制验证签名算法为HS256(Supabase默认使用的算法)
        if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
            return nil, fmt.Errorf("不支持的签名算法: %v", token.Header["alg"])
        }
        return jwtSecret, nil
    })

    if err != nil {
        return nil, err
    }

    if claims, ok := token.Claims.(*SupabaseClaims); ok && token.Valid {
        // 额外检查令牌是否过期
        if time.Now().Unix() > claims.Exp {
            return nil, errors.New("令牌已过期")
        }
        // 可选:验证受众是否匹配你的项目ID
        // if claims.Aud != "你的Supabase项目ID" {
        //     return nil, errors.New("无效的令牌受众")
        // }
        return claims, nil
    }

    return nil, errors.New("无效的令牌")
}

四、HTTP服务中的中间件实现

将验证逻辑封装为HTTP中间件,自动处理请求头中的令牌:

package main

import (
    "context"
    "fmt"
    "log"
    "net/http"
)

// AuthMiddleware JWT验证中间件
func AuthMiddleware(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        authHeader := r.Header.Get("Authorization")
        if authHeader == "" {
            http.Error(w, "缺少Authorization请求头", http.StatusUnauthorized)
            return
        }

        claims, err := ValidateSupabaseJWT(authHeader)
        if err != nil {
            http.Error(w, "令牌验证失败: "+err.Error(), http.StatusUnauthorized)
            return
        }

        // 将验证后的用户信息存入请求上下文
        r = r.WithContext(context.WithValue(r.Context(), "user", claims))
        next.ServeHTTP(w, r)
    })
}

// ProtectedHandler 示例受保护路由
func ProtectedHandler(w http.ResponseWriter, r *http.Request) {
    user := r.Context().Value("user").(*SupabaseClaims)
    w.WriteHeader(http.StatusOK)
    fmt.Fprintf(w, "验证通过!用户邮箱: %s,角色: %s", user.Email, user.Role)
}

func main() {
    mux := http.NewServeMux()
    mux.Handle("/protected", AuthMiddleware(http.HandlerFunc(ProtectedHandler)))

    log.Println("服务启动在 :8080")
    log.Fatal(http.ListenAndServe(":8080", mux))
}

五、测试验证流程

  1. 通过Supabase前端SDK或API获取用户的JWT令牌(例如signInWithPassword接口返回的session.access_token)
  2. 发送GET请求到http://localhost:8080/protected,请求头添加Authorization: Bearer 你的令牌
  3. 验证通过则返回用户信息,失败则返回401错误

内容的提问来源于stack exchange,提问作者SHUBHAM PRAJAPATI

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 03:46:13