package auth import ( "crypto/sha256" "encoding/base64" "encoding/binary" "errors" "fmt" "log" "reflect" "github.com/golang-jwt/jwt" "github.com/zeromicro/go-zero/core/logx" ) type IDTYPE int const ( // 白板用户, 以观众身份命名, 没有接收Cookie, 没有拿到guest_id的用户 IDTYPE_Onlooker IDTYPE = 0 // 登录用户 IDTYPE_User IDTYPE = 1 // 游客 接收授权拿到guest_id的用户 IDTYPE_Guest IDTYPE = 2 ) // DebugData type DebugData struct { DiffTimeLogoCombine int64 `json:"diff_time_logo_combine"` // 合图算法时间 DiffTimeUploadFile int64 `json:"diff_time_upload_file"` // 合图上传时间 } // Debug 相关的结构 type Debug struct { Exp *int64 `json:"exp"` IsCache int64 `json:"is_cache"` // 是否缓存 IsAllTemplateTag int64 `json:"is_all_template_tag"` // 是开启全部模板 } // UserInfo 用户的信息 type UserInfo struct { UserId int64 `json:"user_id"` GuestId int64 `json:"guest_id"` Exp int64 `json:"exp"` //截止有效时间 Debug *Debug `json:"debug,omitempty"` } // GetIdType 用户确认用户身份类型 func (info *UserInfo) GetIdType() IDTYPE { if info.UserId != 0 { return IDTYPE_User } if info.GuestId != 0 { return IDTYPE_Guest } return IDTYPE_Onlooker } // IsUser 用户是不是登录用户 func (info *UserInfo) IsUser() bool { return info.UserId != 0 } // IsGuest 用户是不是游客 func (info *UserInfo) IsGuest() bool { // 必须判断登录用户在前, 用户可能会携带以前是游客到注册的身份 if info.UserId != 0 { return false } if info.GuestId != 0 { return true } return false } // IsOnlooker 白板用户: 非登录用户, 非游客, 判断为白板用户 func (info *UserInfo) IsOnlooker() bool { return info.UserId == 0 && info.GuestId == 0 } type BackendUserInfo struct { UserId int64 `json:"user_id"` DepartmentId int64 `json:"department_id"` } type OAuthInfo struct { Id int64 `json:"id"` Platform string `json:"platform"` } // 获取登录信息 func GetUserInfoFormMapClaims(claims jwt.MapClaims) (*UserInfo, error) { userinfo := &UserInfo{} if exp, ok := claims["exp"]; ok { expire, ok := exp.(float64) if !ok { err := errors.New(fmt.Sprint("parse exp form context err:", exp)) logx.Error("parse exp form context err:", err) return nil, err } userinfo.Exp = int64(expire) } if userid, ok := claims["user_id"]; ok { uid, ok := userid.(float64) if !ok { err := errors.New(fmt.Sprint("parse uid form context err:", userid)) logx.Error("parse uid form context err:", err) return nil, err } userinfo.UserId = int64(uid) } else { err := errors.New(`userid not in claims`) logx.Error(`userid not in claims`) return nil, err } if guestid, ok := claims["guest_id"]; ok { gid, ok := guestid.(float64) if !ok { err := errors.New(fmt.Sprint("parse guestid form context err:", guestid)) logx.Error("parse guestid form context err:", err) return nil, err } userinfo.GuestId = int64(gid) } else { err := errors.New(`userid not in claims`) logx.Error(`userid not in claims`) return nil, err } return userinfo, nil } // GetBackendUserInfoFormMapClaims 获取后台登录信息 func GetBackendUserInfoFormMapClaims(claims jwt.MapClaims) (*BackendUserInfo, error) { userinfo := &BackendUserInfo{} if userid, ok := claims["user_id"]; ok { uid, ok := userid.(float64) if !ok { err := errors.New(fmt.Sprint("parse uid form context err:", userid)) logx.Error("parse uid form context err:", err) return nil, err } userinfo.UserId = int64(uid) } else { err := errors.New(`userid not in claims`) logx.Error(`userid not in claims`) return nil, err } return userinfo, nil } // GenerateJwtTokenUint64 网站jwt token生成 func GenerateJwtTokenUint64(AccessSecret uint64, accessExpire, nowSec int64, userid int64, guestid int64) (string, error) { claims := make(jwt.MapClaims) claims["exp"] = nowSec + accessExpire claims["iat"] = nowSec // if userid == 0 && guestid == 0 { // err := errors.New("userid and guestid cannot be 0 at the same time") // logx.Error(err) // return "", err // } claims["user_id"] = userid claims["guest_id"] = guestid token := jwt.New(jwt.SigningMethodHS256) token.Claims = claims key := make([]byte, 8) binary.BigEndian.PutUint64(key, AccessSecret) return token.SignedString(key) } // GenerateBaseJwtTokenUint64 网站jwt token生成 func GenerateBaseJwtTokenUint64(AccessSecret uint64, accessExpire int64, nowSec int64, myclaims any) (string, error) { claims := make(jwt.MapClaims) claims["exp"] = nowSec + accessExpire claims["iat"] = nowSec // if userid == 0 && guestid == 0 { // err := errors.New("userid and guestid cannot be 0 at the same time") // logx.Error(err) // return "", err // } // 使用反射获取 MyClaims 结构体的类型和值 myclaimsType := reflect.TypeOf(myclaims) if myclaimsType.Kind() != reflect.Ptr { log.Println(myclaimsType.Kind()) panic("myclaimsType must be ptr") } myclaimsType = myclaimsType.Elem() myclaimsValue := reflect.ValueOf(myclaims).Elem() // 遍历 MyClaims 结构体的字段 for i := 0; i < myclaimsType.NumField(); i++ { field := myclaimsType.Field(i) tag := field.Tag.Get("json") if tag == "exp" || tag == "iat" { continue } value := myclaimsValue.Field(i).Interface() // 将字段值赋给 claims 对象的相应键 claims[tag] = value } token := jwt.New(jwt.SigningMethodHS256) token.Claims = claims key := make([]byte, 8) binary.BigEndian.PutUint64(key, AccessSecret) return token.SignedString(key) } // GenerateJwtToken 网站jwt token生成 func GenerateJwtToken(accessSecret *string, accessExpire, nowSec int64, userid int64, guestid int64) (string, error) { claims := make(jwt.MapClaims) claims["exp"] = nowSec + accessExpire claims["iat"] = nowSec if userid == 0 && guestid == 0 { err := errors.New("userid and guestid cannot be 0 at the same time") logx.Error(err) return "", err } claims["user_id"] = userid claims["guest_id"] = guestid token := jwt.New(jwt.SigningMethodHS256) token.Claims = claims return token.SignedString([]byte(*accessSecret)) } // GenerateBackendJwtToken 后台jwt token生成 func GenerateBackendJwtToken(accessSecret *string, accessExpire, nowSec int64, userId int64, departmentId int64) (string, error) { claims := make(jwt.MapClaims) claims["exp"] = nowSec + accessExpire claims["iat"] = nowSec if userId == 0 { err := errors.New("userId cannot be 0 at the same time") logx.Error(err) return "", err } claims["user_id"] = userId claims["department_id"] = departmentId token := jwt.New(jwt.SigningMethodHS256) token.Claims = claims return token.SignedString([]byte(*accessSecret)) } func getJwtClaims(AuthKey string, AccessSecret *string) (jwt.MapClaims, error) { token, err := jwt.Parse(AuthKey, func(token *jwt.Token) (interface{}, error) { // 检查签名方法是否为 HS256 if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) } // 返回用于验证签名的密钥 return []byte(*AccessSecret), nil }) if err != nil { return nil, errors.New(fmt.Sprint("Error parsing token:", err)) } // 验证成功返回 if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { return claims, nil } return nil, errors.New(fmt.Sprint("Invalid token", err)) } func PasswordHash(pwd string) string { h := sha256.New() h.Write([]byte(pwd)) return base64.RawURLEncoding.EncodeToString(h.Sum(nil)) } func CheckValueRange[T comparable](v T, rangevalues ...T) bool { for _, rv := range rangevalues { if v == rv { return true } } return false } // GenerateRegisterToken 网站注册 token生成 func GenerateRegisterToken(accessSecret *string, accessExpire, nowSec int64, id int64, platform string) (string, error) { claims := make(jwt.MapClaims) claims["exp"] = nowSec + accessExpire claims["iat"] = nowSec if id == 0 { err := errors.New("userid and guestid cannot be 0 at the same time") logx.Error(err) return "", err } claims["id"] = id claims["platform"] = platform token := jwt.New(jwt.SigningMethodHS256) token.Claims = claims return token.SignedString([]byte(*accessSecret)) } // GetRegisterFormMapClaims 获取注册唯一token标识登录信息 func GetRegisterFormMapClaims(claims jwt.MapClaims) (*OAuthInfo, error) { oauthinfo := &OAuthInfo{} if userid, ok := claims["id"]; ok { uid, ok := userid.(float64) if !ok { err := errors.New(fmt.Sprint("parse uid form context err:", userid)) logx.Error("parse uid form context err:", err) return nil, err } oauthinfo.Id = int64(uid) } else { err := errors.New(`id not in claims`) logx.Error(`id not in claims`) return nil, err } if splatform, ok := claims["id"]; ok { platform, ok := splatform.(string) if !ok { err := errors.New(fmt.Sprint("parse uid form context err:", platform)) logx.Error("parse uid form context err:", err) return nil, err } oauthinfo.Platform = platform } else { err := errors.New(`id not in claims`) logx.Error(`id not in claims`) return nil, err } return oauthinfo, nil } func getRegisterJwtClaims(Token string, AccessSecret *string) (jwt.MapClaims, error) { token, err := jwt.Parse(Token, func(token *jwt.Token) (interface{}, error) { // 检查签名方法是否为 HS256 if _, ok := token.Method.(*jwt.SigningMethodHMAC); !ok { return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"]) } // 返回用于验证签名的密钥 return []byte(*AccessSecret), nil }) if err != nil { return nil, errors.New(fmt.Sprint("Error parsing token:", err)) } // 验证成功返回 if claims, ok := token.Claims.(jwt.MapClaims); ok && token.Valid { return claims, nil } return nil, errors.New(fmt.Sprint("Invalid token", err)) }