Files
36Wisdom/common/auth/auth.go
T
2026-08-14 13:34:21 +08:00

82 lines
2.4 KiB
Go

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 <token>,注入 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
}