github.com/SupenBysz/gf-admin-community@v0.7.4/internal/logic/sys_jwt/sys_jwt.go (about) 1 package sys_jwt 2 3 import ( 4 "context" 5 "github.com/SupenBysz/gf-admin-community/sys_model" 6 "github.com/SupenBysz/gf-admin-community/sys_model/sys_enum" 7 "github.com/SupenBysz/gf-admin-community/sys_model/sys_hook" 8 "github.com/SupenBysz/gf-admin-community/sys_service" 9 "github.com/SupenBysz/gf-admin-community/utility/response" 10 "github.com/yitter/idgenerator-go/idgen" 11 "time" 12 13 "github.com/gogf/gf/v2/errors/gerror" 14 "github.com/gogf/gf/v2/frame/g" 15 "github.com/gogf/gf/v2/net/ghttp" 16 "github.com/gogf/gf/v2/os/gctx" 17 "github.com/gogf/gf/v2/text/gstr" 18 "github.com/golang-jwt/jwt/v4" 19 "golang.org/x/sync/singleflight" 20 ) 21 22 type hookInfo sys_model.KeyValueT[int64, sys_hook.JwtHookInfo] 23 24 type sJwt struct { 25 SigningKey []byte 26 hookArr []hookInfo 27 } 28 29 var ( 30 ConcurrencyControl = &singleflight.Group{} 31 ) 32 33 func init() { 34 sys_service.RegisterJwt(New()) 35 } 36 37 // New MiddlewareJwt 权限控制 38 func New() *sJwt { 39 return &sJwt{ 40 SigningKey: []byte(g.Cfg().MustGet(gctx.New(), "service.tokenSignKey").String()), 41 } 42 } 43 44 // InstallHook 安装Hook 45 func (s *sJwt) InstallHook(userType sys_enum.UserType, hookFunc sys_hook.JwtHookFunc) int64 { 46 item := hookInfo{Key: idgen.NextId(), Value: sys_hook.JwtHookInfo{Key: userType, Value: hookFunc}} 47 48 s.hookArr = append(s.hookArr, item) 49 return item.Key 50 } 51 52 // UnInstallHook 卸载Hook 53 func (s *sJwt) UnInstallHook(savedHookId int64) { 54 newFuncArr := make([]hookInfo, 0) 55 for _, item := range s.hookArr { 56 if item.Key != savedHookId { 57 newFuncArr = append(newFuncArr, item) 58 continue 59 } 60 } 61 s.hookArr = newFuncArr 62 } 63 64 // CleanAllHook 清除所有Hook 65 func (s *sJwt) CleanAllHook() { 66 s.hookArr = make([]hookInfo, 0) 67 } 68 69 // GenerateToken 创建一个token 70 func (s *sJwt) GenerateToken(ctx context.Context, user *sys_model.SysUser) (response *sys_model.TokenInfo, err error) { 71 user.Password = "" 72 73 customClaims := &sys_model.JwtCustomClaims{ 74 SysUser: *user, 75 IsSuperAdmin: user.Type == sys_enum.User.Type.SuperAdmin.Code(), 76 IsAdmin: user.Type == sys_enum.User.Type.Admin.Code(), 77 78 RegisteredClaims: jwt.RegisteredClaims{ 79 NotBefore: jwt.NewNumericDate(time.Now()), 80 ExpiresAt: jwt.NewNumericDate(time.Now().Add(time.Hour * 24 * 7)), 81 IssuedAt: jwt.NewNumericDate(time.Now()), 82 Issuer: "免啦街", 83 Subject: "筷满客", 84 }, 85 } 86 87 g.Try(ctx, func(ctx context.Context) { 88 for _, hook := range s.hookArr { 89 if hook.Value.Key.Code()&user.Type == user.Type || (user.Type == 64 && hook.Value.Key.Code() == 32) { 90 customClaims, err = hook.Value.Value(ctx, customClaims) 91 if err != nil { 92 break 93 } 94 } 95 } 96 }) 97 98 token, err := s.CreateToken(customClaims) 99 100 if err != nil { 101 return nil, gerror.New("创建登录令牌失败") 102 } 103 104 return &sys_model.TokenInfo{ 105 Token: token, 106 ExpireAt: customClaims.RegisteredClaims.ExpiresAt.Time, 107 }, nil 108 } 109 110 // CreateToken 创建一个token 111 func (s *sJwt) CreateToken(claims *sys_model.JwtCustomClaims) (string, error) { 112 token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims) 113 return token.SignedString(s.SigningKey) 114 } 115 116 // RefreshToken 刷新Token,并发安全 117 func (s *sJwt) RefreshToken(oldToken string, claims *sys_model.JwtCustomClaims) (string, error) { 118 v, err, _ := ConcurrencyControl.Do("JWT:"+oldToken, func() (interface{}, error) { 119 return s.CreateToken(claims) 120 }) 121 return v.(string), err 122 } 123 124 func (s *sJwt) Middleware(r *ghttp.Request) { 125 tokenString := gstr.Trim(r.Header.Get("Authorization")) 126 127 if gstr.ToUpper(r.Method) == "GET" && tokenString == "" { 128 tokenString = r.GetParam("token", "").String() 129 } 130 131 s.MakeSession(r.Context(), tokenString) 132 return 133 } 134 135 func (s *sJwt) MakeSession(ctx context.Context, tokenString string) *sys_model.JwtCustomClaims { 136 if gstr.HasPrefix(tokenString, "Bearer ") { 137 tokenString = gstr.SubStr(tokenString, 7) 138 } 139 140 token, err := jwt.ParseWithClaims(tokenString, &sys_model.JwtCustomClaims{}, func(token *jwt.Token) (i interface{}, e error) { 141 return s.SigningKey, nil 142 }) 143 144 isCustomSession := sys_service.SysSession().HasCustom(ctx) 145 146 if err != nil { 147 if ve, ok := err.(*jwt.ValidationError); ok { 148 if ve.Errors&jwt.ValidationErrorMalformed != 0 { 149 err = gerror.New("无效TOKEN") 150 } else if ve.Errors&jwt.ValidationErrorExpired != 0 { 151 // Token is expired 152 err = gerror.New("TOKEN 已过期") 153 } else if ve.Errors&jwt.ValidationErrorNotValidYet != 0 { 154 err = gerror.New("TOKEN 未激活") 155 } else if ve.Errors&jwt.ValidationErrorSignatureInvalid != 0 { 156 err = gerror.New("TOKEN 签名无效") 157 } else { 158 err = gerror.New("解析TOKEN失败") 159 } 160 } 161 if !isCustomSession { 162 response.JsonExit(g.RequestFromCtx(ctx), 401, err.Error()) 163 } 164 return nil 165 } 166 167 if token != nil { 168 if claims, ok := token.Claims.(*sys_model.JwtCustomClaims); ok && token.Valid { 169 if !isCustomSession { 170 sys_service.SysSession().SetUser(ctx, claims) 171 g.RequestFromCtx(ctx).Middleware.Next() 172 } 173 return claims 174 } 175 } 176 177 if !isCustomSession { 178 response.JsonExit(g.RequestFromCtx(ctx), 401, "解析TOKEN失败") 179 } 180 return nil 181 }