如何将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)) }
五、测试验证流程
- 通过Supabase前端SDK或API获取用户的JWT令牌(例如
signInWithPassword接口返回的session.access_token) - 发送GET请求到
http://localhost:8080/protected,请求头添加Authorization: Bearer 你的令牌 - 验证通过则返回用户信息,失败则返回401错误
内容的提问来源于stack exchange,提问作者SHUBHAM PRAJAPATI
相关产品推荐
相关产品推荐

