Files
2026-09-17 14:42:44 +08:00

122 lines
3.1 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package logic
import (
"context"
"errors"
"strings"
"time"
"github.com/gogf/gf/v2/frame/g"
"github.com/gogf/gf/v2/net/ghttp"
"github.com/gogf/gf/v2/os/gctx"
"github.com/golang-jwt/jwt/v5"
"tool-api/internal/consts"
)
type jwtClaims struct {
UserId int64 `json:"userId,omitempty"`
LevelKey string `json:"levelKey,omitempty"`
NickName string `json:"nickName,omitempty"`
RoleName string `json:"roleName,omitempty"`
RoleValue string `json:"roleValue,omitempty"`
jwt.RegisteredClaims
}
func jwtSecret(ctx context.Context) []byte {
return []byte(g.Cfg().MustGet(ctx, "jwt.secret", "tool-box-secret-change-me").String())
}
// IssueToken 签发 JWT;aud 区分 user / admin
func IssueToken(ctx context.Context, aud string, userId int64, extra map[string]string) (string, error) {
hours := g.Cfg().MustGet(ctx, "jwt.expireHours", 168).Int()
claims := jwtClaims{
UserId: userId,
RegisteredClaims: jwt.RegisteredClaims{
Audience: jwt.ClaimStrings{aud},
Issuer: "tool-api",
IssuedAt: jwt.NewNumericDate(time.Now()),
ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Duration(hours) * time.Hour)),
},
}
for k, v := range extra {
switch k {
case "levelKey":
claims.LevelKey = v
case "nickName":
claims.NickName = v
case "roleName":
claims.RoleName = v
case "roleValue":
claims.RoleValue = v
}
}
return jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString(jwtSecret(ctx))
}
func ParseToken(tokenStr, aud string) (*jwtClaims, error) {
claims := &jwtClaims{}
_, err := jwt.ParseWithClaims(tokenStr, claims, func(t *jwt.Token) (interface{}, error) {
return jwtSecret(gctx.GetInitCtx()), nil
}, jwt.WithValidMethods([]string{"HS256"}), jwt.WithAudience(aud))
if err != nil {
return nil, err
}
return claims, nil
}
func parseBearer(r *ghttp.Request, aud string) (*jwtClaims, error) {
auth := r.Header.Get("Authorization")
tokenStr := strings.TrimPrefix(auth, "Bearer ")
if tokenStr == "" {
return nil, errors.New("empty token")
}
return ParseToken(tokenStr, aud)
}
func writeAuthFail(r *ghttp.Request) {
r.Response.WriteJson(g.Map{"code": 401, "message": "登录已失效,请重新登录", "result": nil})
r.Exit()
}
// UserAuth 小程序用户鉴权
func UserAuth(r *ghttp.Request) {
claims, err := parseBearer(r, consts.AudUser)
if err != nil {
writeAuthFail(r)
return
}
r.SetCtxVar(consts.CtxUserId, claims.UserId)
r.SetCtxVar(consts.CtxLevelKey, claims.LevelKey)
r.Middleware.Next()
}
// AdminAuth 管理端鉴权
func AdminAuth(r *ghttp.Request) {
claims, err := parseBearer(r, consts.AudAdmin)
if err != nil {
writeAuthFail(r)
return
}
r.SetCtxVar(consts.CtxAdminId, claims.UserId)
r.Middleware.Next()
}
// ===== 业务上下文取值 =====
func CtxUserId(ctx context.Context) int64 {
return g.RequestFromCtx(ctx).GetCtxVar(consts.CtxUserId).Int64()
}
func CtxLevelKey(ctx context.Context) string {
return g.RequestFromCtx(ctx).GetCtxVar(consts.CtxLevelKey).String()
}
func CtxAdminId(ctx context.Context) int64 {
return g.RequestFromCtx(ctx).GetCtxVar(consts.CtxAdminId).Int64()
}
func IsDebug(ctx context.Context) bool {
return g.Cfg().MustGet(ctx, "debug", false).Bool()
}