122 lines
3.1 KiB
Go
122 lines
3.1 KiB
Go
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()
|
||
}
|