package auth import ( "context" "strings" "time" "github.com/golang-jwt/jwt/v5" "github.com/gogf/gf/v2/errors/gerror" "github.com/gogf/gf/v2/frame/g" "github.com/gogf/gf/v2/net/ghttp" "github.com/gogf/gf/v2/util/gconv" ) // ctxKey 注入 request context 的键名。 type ctxKey string const ( keyUid ctxKey = "authUid" keyRole ctxKey = "authRole" ) // GenerateToken 签发 HS256 JWT。 func GenerateToken(secret string, uid int64, role string, expireSeconds int) (string, error) { claims := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ "uid": uid, "role": role, "exp": time.Now().Add(time.Duration(expireSeconds) * time.Second).Unix(), }) return claims.SignedString([]byte(secret)) } // Secret 鉴权密钥(config.yml auth.secret),token 签发与解析共用入口。 func Secret(ctx context.Context) string { return g.Cfg().MustGet(ctx, "auth.secret").String() } // ParseToken 校验并解析 token,返回 uid 与 role。 func ParseToken(secret, tokenString string) (uid int64, role string, err error) { token, err := jwt.Parse(tokenString, func(t *jwt.Token) (any, error) { return []byte(secret), nil }) if err != nil || !token.Valid { return 0, "", gerror.New("登录状态已失效,请重新登录") } claims, ok := token.Claims.(jwt.MapClaims) if !ok { return 0, "", gerror.New("登录状态解析失败") } return gconv.Int64(claims["uid"]), gconv.String(claims["role"]), nil } // Middleware 校验 Authorization: Bearer ,注入 uid/role 到请求上下文。 // requiredRole 为空表示任意登录角色;非空则额外校验角色匹配。 func Middleware(secret, requiredRole string) ghttp.HandlerFunc { return func(r *ghttp.Request) { tokenString := strings.TrimPrefix(r.Header.Get("Authorization"), "Bearer ") if tokenString == "" { r.Response.WriteStatusExit(401, "未登录") } uid, role, err := ParseToken(secret, tokenString) if err != nil { r.Response.WriteStatusExit(401, err.Error()) } if requiredRole != "" && role != requiredRole { r.Response.WriteStatusExit(403, "无权限访问") } r.SetCtxVar(string(keyUid), uid) r.SetCtxVar(string(keyRole), role) r.Middleware.Next() } } // GetUid 从请求上下文取登录 uid(未登录返回 0)。 func GetUid(ctx context.Context) int64 { if req := g.RequestFromCtx(ctx); req != nil { return gconv.Int64(req.GetCtxVar(string(keyUid)).Val()) } return 0 }