package token import ( "encoding/json" "fmt" "time" "github.com/golang-jwt/jwt/v5" "be.ems/src/framework/config" "be.ems/src/framework/constants" "be.ems/src/framework/database/redis" "be.ems/src/framework/logger" "be.ems/src/framework/utils/parse" ) // UserTokenCreate 生成令牌 // userId 用户ID // deviceFingerprint 设备指纹 SHA256 // tokenType 令牌类型 access:访问令牌 refresh:刷新令牌 func UserTokenCreate(userId int64, deviceFingerprint, tokenType string) (string, int64) { // 令牌算法 HS256 HS384 HS512 algorithm := config.Get("jwt.algorithm").(string) var method *jwt.SigningMethodHMAC switch algorithm { case "HS512": method = jwt.SigningMethodHS512 case "HS384": method = jwt.SigningMethodHS384 default: // 包含HS256和其他所有情况 method = jwt.SigningMethodHS256 } // 生成令牌设置密钥 secret := fmt.Sprint(config.Get("jwt.secret")) // 设置令牌过期时间 now := time.Now() exp := now if tokenType == "access" { expiresIn := time.Duration(parse.Number(config.Get("jwt.expiresIn"))) exp = now.Add(expiresIn * time.Minute) secret = "User_Access:" + secret } if tokenType == "refresh" { refreshIn := time.Duration(parse.Number(config.Get("jwt.refreshIn"))) exp = now.Add(refreshIn * time.Minute) secret = "User_Refresh:" + secret } // 生成令牌负荷绑定uuid标识 jwtToken := jwt.NewWithClaims(method, jwt.MapClaims{ constants.JWT_DEVICE_ID: deviceFingerprint, constants.JWT_USER_ID: userId, "exp": exp.Unix(), // 过期时间 "iat": now.Unix(), // 签发时间 "nbf": now.Add(-10 * time.Second).Unix(), // 生效时间 }) tokenStr, err := jwtToken.SignedString([]byte(secret)) if err != nil { logger.Infof("jwt sign err : %v", err) return "", 0 } expSeconds := int64(exp.Sub(now).Seconds()) return tokenStr, expSeconds } // UserTokenVerify 校验令牌是否有效 // tokenType 令牌类型 access:访问令牌 refresh:刷新令牌 func UserTokenVerify(tokenStr string, tokenType string) (jwt.MapClaims, error) { jwtToken, err := jwt.Parse(tokenStr, func(jToken *jwt.Token) (any, error) { // 判断加密算法是预期的加密算法 if _, ok := jToken.Method.(*jwt.SigningMethodHMAC); ok { secret := config.Get("jwt.secret").(string) if tokenType == "access" { secret = "User_Access:" + secret } if tokenType == "refresh" { secret = "User_Refresh:" + secret } return []byte(secret), nil } return nil, jwt.ErrSignatureInvalid }) if err != nil { logger.Errorf("Token Verify Err: %v", err) return nil, fmt.Errorf("token invalid") } // 如果解析负荷成功并通过签名校验 claims, ok := jwtToken.Claims.(jwt.MapClaims) if ok && jwtToken.Valid { return claims, nil } return nil, fmt.Errorf("token valid error") } // UserInfoRemove 清除访问用户信息缓存 func UserInfoRemove(tokenStr string) (string, error) { claims, err := UserTokenVerify(tokenStr, "access") if err != nil { logger.Errorf("token verify err %v", err) return "", err } info := UserInfoGet(claims) if info.User.UserName != "" { // 清除缓存KEY deviceId := fmt.Sprint(claims[constants.JWT_DEVICE_ID]) tokenKey := constants.CACHE_TOKEN_DEVICE + ":" + deviceId return info.User.UserName, redis.Del("", tokenKey) } return "", fmt.Errorf("token invalid") } // UserInfoCreate 生成访问用户信息缓存 func UserInfoCreate(info *UserInfo, deviceFingerprint string, ilobArr [4]string) { info.DeviceId = deviceFingerprint // 设置请求用户登录客户端 info.LoginIp = ilobArr[0] info.LoginLocation = ilobArr[1] info.OS = ilobArr[2] info.Browser = ilobArr[3] expiresIn := time.Duration(parse.Number(config.Get("jwt.expiresIn"))) now := time.Now() exp := now.Add(expiresIn * time.Minute) info.LoginTime = now.UnixMilli() info.ExpireTime = exp.UnixMilli() // 设置新登录IP和登录时间 info.User.LoginIp = info.LoginIp info.User.LoginTime = info.LoginTime info.User.Password = "" // 登录信息标识缓存 tokenKey := constants.CACHE_TOKEN_DEVICE + ":" + info.DeviceId jsonBytes, err := json.Marshal(info) if err != nil { return } _ = redis.Set("", tokenKey, string(jsonBytes), expiresIn*time.Minute) } // UserInfoUpdate 更新访问用户信息缓存 func UserInfoUpdate(info UserInfo) { info.User.Password = "" // 登录信息标识缓存 tokenKey := constants.CACHE_TOKEN_DEVICE + ":" + info.DeviceId jsonBytes, err := json.Marshal(info) if err != nil { return } expiresIn, _ := redis.GetExpire("", tokenKey) expiration := time.Duration(expiresIn) * time.Second _ = redis.Set("", tokenKey, string(jsonBytes), expiration) } // UserInfoGet 缓存的访问用户信息 func UserInfoGet(claims jwt.MapClaims) UserInfo { info := UserInfo{} deviceId := fmt.Sprint(claims[constants.JWT_DEVICE_ID]) tokenKey := constants.CACHE_TOKEN_DEVICE + ":" + deviceId hasKey, err := redis.Has("", tokenKey) if hasKey > 0 && err == nil { infoStr, err := redis.Get("", tokenKey) if infoStr == "" || err != nil { return info } if err := json.Unmarshal([]byte(infoStr), &info); err != nil { logger.Errorf("info json err : %v", err) return info } } return info }