Golang后端API怎么实现JWT身份验证

来源:我的博客作者:灯下变量头衔:程序员
导读:本期聚焦于小伙伴创作的《Golang后端API怎么实现JWT身份验证》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《Golang后端API怎么实现JWT身份验证》有用,将其分享出去将是对创作者最好的鼓励。

在Golang后端开发中,为API接口添加身份验证是保障服务安全的基础操作,JWT(JSON Web Token)凭借无状态、易扩展的特性,成为API认证的主流方案。下面我们将完整实现Golang后端API的JWT身份验证逻辑。

Golang后端API怎么实现JWT身份验证

JWT核心原理简述

JWT本质是一个经过签名的JSON格式字符串,由三部分组成,分别是头部(Header)、载荷(Payload)、签名(Signature),三部分之间用点号分隔。服务端生成JWT后返回给客户端,客户端后续请求API时在请求头中携带该令牌,服务端校验令牌合法性后即可确认用户身份。

环境准备与依赖安装

我们需要使用Golang的第三方JWT库来简化开发,这里选择社区常用的github.com/golang-jwt/jwt/v5库,执行以下命令安装依赖:

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

JWT生成逻辑实现

首先定义JWT的相关配置,包括签名密钥、令牌过期时间等,然后实现生成JWT的函数:

package main

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

// 定义JWT签名密钥,实际项目中建议从配置文件读取,不要硬编码
var jwtKey = []byte("your_secret_key_here")

// 定义载荷中存储的自定义字段结构
type Claims struct {
	UserID uint64 `json:"user_id"`
	Username string `json:"username"`
	jwt.RegisteredClaims
}

// 生成JWT令牌的函数
func GenerateJWT(userID uint64, username string) (string, error) {
	// 设置令牌过期时间为2小时
	expirationTime := time.Now().Add(2 * time.Hour)
	// 初始化载荷
	claims := &Claims{
		UserID: userID,
		Username: username,
		RegisteredClaims: jwt.RegisteredClaims{
			ExpiresAt: jwt.NewNumericDate(expirationTime),
			IssuedAt:  jwt.NewNumericDate(time.Now()),
			Issuer:    "golang_api_demo",
		},
	}
	// 使用HS256签名算法生成令牌
	token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
	// 签名并返回令牌字符串
	return token.SignedString(jwtKey)
}

JWT校验逻辑实现

生成令牌后,需要实现校验令牌合法性的函数,用于后续接口鉴权时调用:

// 校验JWT令牌的函数,返回解析后的载荷和错误
func ParseJWT(tokenStr string) (*Claims, error) {
	claims := &Claims{}
	// 解析令牌
	token, err := jwt.ParseWithClaims(tokenStr, claims, func(token *jwt.Token) (interface{}, error) {
		// 校验签名算法是否为预期的HS256
		if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok {
			return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
		}
		return jwtKey, nil
	})
	if err != nil {
		return nil, err
	}
	// 校验令牌是否有效
	if !token.Valid {
		return nil, fmt.Errorf("invalid token")
	}
	return claims, nil
}

API接口鉴权中间件实现

为了避免在每个接口中重复编写令牌校验逻辑,我们可以实现一个HTTP中间件,统一处理所有需要认证的接口的鉴权逻辑:

package main

import (
	"fmt"
	"net/http"
	"strings"
)

// JWT鉴权中间件
func JWTAuthMiddleware(next http.HandlerFunc) http.HandlerFunc {
	return func(w http.ResponseWriter, r *http.Request) {
		// 从请求头Authorization中获取令牌,格式为Bearer {token}
		authHeader := r.Header.Get("Authorization")
		if authHeader == "" {
			http.Error(w, "缺少认证令牌", http.StatusUnauthorized)
			return
		}
		// 分割Bearer和令牌字符串
		parts := strings.SplitN(authHeader, " ", 2)
		if len(parts) != 2 || parts[0] != "Bearer" {
			http.Error(w, "认证令牌格式错误", http.StatusUnauthorized)
			return
		}
		tokenStr := parts[1]
		// 校验令牌
		claims, err := ParseJWT(tokenStr)
		if err != nil {
			http.Error(w, fmt.Sprintf("令牌校验失败: %v", err), http.StatusUnauthorized)
			return
		}
		// 可以将用户信息存入请求上下文,后续接口可以直接获取
		ctx := r.Context()
		ctx = context.WithValue(ctx, "user_id", claims.UserID)
		ctx = context.WithValue(ctx, "username", claims.Username)
		// 调用下一个处理函数
		next(w, r.WithContext(ctx))
	}
}

完整接口示例

下面我们实现两个接口,一个是登录接口用于生成JWT,另一个是用户信息接口需要JWT鉴权才能访问:

package main

import (
	"context"
	"encoding/json"
	"net/http"
)

// 登录请求结构
type LoginRequest struct {
	Username string `json:"username"`
	Password string `json:"password"`
}

// 登录接口处理函数
func LoginHandler(w http.ResponseWriter, r *http.Request) {
	if r.Method != http.MethodPost {
		http.Error(w, "请求方法不支持", http.StatusMethodNotAllowed)
		return
	}
	var req LoginRequest
	if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
		http.Error(w, "请求参数错误", http.StatusBadRequest)
		return
	}
	// 这里简化用户校验逻辑,实际项目中需要查询数据库校验用户名密码
	if req.Username == "test" && req.Password == "123456" {
		// 生成JWT令牌
		token, err := GenerateJWT(1, req.Username)
		if err != nil {
			http.Error(w, "生成令牌失败", http.StatusInternalServerError)
			return
		}
		w.Header().Set("Content-Type", "application/json")
		json.NewEncoder(w).Encode(map[string]string{
			"token": token,
		})
		return
	}
	http.Error(w, "用户名或密码错误", http.StatusUnauthorized)
}

// 获取用户信息接口处理函数,需要鉴权
func UserInfoHandler(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	// 从上下文获取用户信息
	userID, _ := ctx.Value("user_id").(uint64)
	username, _ := ctx.Value("username").(string)
	w.Header().Set("Content-Type", "application/json")
	json.NewEncoder(w).Encode(map[string]interface{}{
		"user_id":  userID,
		"username": username,
	})
}

func main() {
	// 注册路由
	http.HandleFunc("/login", LoginHandler)
	// 用户信息接口使用鉴权中间件
	http.HandleFunc("/user/info", JWTAuthMiddleware(UserInfoHandler))
	// 启动服务
	fmt.Println("服务启动在 :8080 端口")
	http.ListenAndServe(":8080", nil)
}

注意事项

  • 签名密钥需要妥善保管,不要泄露,生产环境建议通过配置文件或环境变量注入,不要硬编码在代码中。
  • 令牌过期时间需要根据业务场景合理设置,过短会增加客户端刷新令牌的频率,过长会增加令牌泄露后的安全风险。
  • 如果需要在令牌过期前刷新令牌,可以额外实现刷新令牌接口,校验旧令牌未过期且合法后生成新的令牌。
  • 中间件中可以根据业务需求扩展校验逻辑,比如校验用户是否被禁用、令牌是否在黑名单中等。

GolangJWTAPI认证后端开发修改时间:2026-07-15 05:54:29

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。