Files
exchange_go/pkg/cryptohelper/jwthelper/jwthelper.go
2025-02-06 11:14:33 +08:00

296 lines
8.2 KiB
Go
Raw 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 jwthelper
import (
"go-admin/common/const/rediskey"
"go-admin/common/helper"
"go-admin/pkg/utility"
"github.com/golang-jwt/jwt/v5"
"go.uber.org/zap"
"fmt"
"strings"
"time"
log "github.com/go-admin-team/go-admin-core/logger"
)
// LoginUserJwt 用户登入信息
type LoginUserJwt struct {
UserID int
NickName string
Phone string
Email string
OsType int
}
// LoginClaims 自定义声明结构体并内嵌jwt.StandardClaims
// jwt包自带的jwt.StandardClaims只包含了官方字段
// 我们这里需要额外记录一个nickname字段所以要自定义结构体
// 如果想要保存更多信息,都可以添加到这个结构体中
type LoginClaims struct {
UserID int `json:"userid"`
NickName string `json:"nickname"`
Phone string `json:"phone"`
Email string `json:"email"`
jwt.RegisteredClaims
}
// JwtSigningKey Jwt signing key
var JwtSigningKey = []byte("tokexapp.com")
var LoginTokenValidTime = 48 * time.Hour // 登录验证token有效期
var LoginAdminTokenValidTime = 24 * time.Hour
var TokenNotValid = -1 // Token无效
var TokenExpire = -2 // Token过期
var TokenSuccess = 1 // Token正常
// CreateJwtToken 创建用户jwt token
func CreateJwtToken(userJwt LoginUserJwt, minute int) (string, string) {
// 创建一个我们自己的声明
expire := time.Now().Add(time.Minute * time.Duration(minute)) //.Unix()
claims := LoginClaims{
UserID: userJwt.UserID,
Phone: userJwt.Phone,
NickName: userJwt.NickName,
Email: userJwt.Email,
RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(expire),
Issuer: "Tokex", // 签发人
},
}
// 使用指定的签名方法创建签名对象
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenStr, err := token.SignedString(JwtSigningKey)
if err != nil {
log.Error("获取jwt token失败:", zap.Error(err))
return "", ""
}
return tokenStr, fmt.Sprintf("%v", expire.Unix())
}
// MidValidToken 检验token是否有效,返回token解密后的string
func MidValidToken(tokenStr string, source int) (int, string) {
// 解析token
token, err := jwt.ParseWithClaims(tokenStr, &LoginClaims{}, func(token *jwt.Token) (i interface{}, err error) {
return JwtSigningKey, nil
})
if err != nil {
if strings.Contains(err.Error(), "token is expired") {
return TokenExpire, ""
}
// loghelper.Error("MidValidToken解析token失败", zap.Error(err))
return TokenNotValid, ""
}
if !token.Valid {
log.Error("MidValidToken解析token无效", zap.Error(err))
return TokenNotValid, ""
}
claims, ok := token.Claims.(*LoginClaims)
if !ok {
return TokenNotValid, ""
}
// 校验token
key := fmt.Sprintf(rediskey.AppLoginUserToken, claims.UserID)
if source == 3 {
key = fmt.Sprintf(rediskey.PCLoginUserToken, claims.UserID)
}
appToken, _ := helper.DefaultRedis.GetString(key)
if len(appToken) == 0 {
//说明未登入或者过期
return TokenExpire, ""
}
if appToken != tokenStr {
//说明是被t
return TokenExpire, ""
}
return TokenSuccess, strings.Join([]string{utility.IntToString(claims.UserID),
claims.NickName, claims.Phone, claims.Email}, ",")
}
// GetLoginUserJwt 解析用户登入信息
func GetLoginUserJwt(tokenStr string) LoginUserJwt {
if len(tokenStr) == 0 {
return LoginUserJwt{}
}
tokenArr := strings.Split(tokenStr, ",")
arrLen := len(tokenArr)
item := LoginUserJwt{
UserID: utility.StringAsInteger(tokenArr[0]),
}
if arrLen > 1 {
item.NickName = tokenArr[1]
}
if arrLen > 2 {
item.Phone = tokenArr[2]
}
if arrLen > 3 {
item.Email = tokenArr[3]
}
return item
}
// AgentLoginJwt ==============Agent 代理商 JWT========================//
type AgentLoginJwt struct {
AgentId int `json:"agent_id"` // 代理商ID
UserId int `json:"user_id"` // 代理商关联的用户ID
Name string `json:"name"` // 代理商姓名
Email string `json:"email"` // 代理商邮件
IP string `json:"ip"` // 代理商IP
}
type AgentLoginClaims struct {
AgentId int `json:"agent_id"` // 代理商ID
UserId int `json:"user_id"` // 代理商关联的用户ID
Name string `json:"name"` // 代理商姓名
Email string `json:"email"` // 代理商邮件
IP string `json:"ip"` // 代理商IP
jwt.RegisteredClaims //StandardClaims
}
var JwtAgentSigningKey = []byte("tokexagent.com") //Jwt signing key
// CreateAgentJwtToken 代理商产生的token
func CreateAgentJwtToken(userJwt AgentLoginJwt, minute int) string {
// 创建一个我们自己的声明
exp := time.Now().Add(time.Minute * time.Duration(minute))
c := AgentLoginClaims{
userJwt.AgentId,
userJwt.UserId, // 自定义字段
userJwt.Name,
userJwt.Email,
userJwt.IP,
jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(exp), // 过期时间
Issuer: "Tokex-Agent", // 签发人
},
}
// 使用指定的签名方法创建签名对象
token := jwt.NewWithClaims(jwt.SigningMethodHS256, c)
tokenStr, err := token.SignedString(JwtAgentSigningKey)
if err != nil {
log.Error("获取jwt token失败:", zap.Error(err))
return ""
}
return tokenStr
}
// MidValidAgentToken 检验token是否有效,返回token解密后的string
func MidValidAgentToken(tokenStr string) (int, string) {
// 解析token
token, err := jwt.ParseWithClaims(tokenStr, &AgentLoginClaims{}, func(token *jwt.Token) (i interface{}, err error) {
return JwtAgentSigningKey, nil
})
if err != nil {
return TokenNotValid, ""
}
if !token.Valid {
log.Error("MidValidAgentToken解析token无效", zap.Error(err))
return TokenNotValid, ""
}
claims, ok := token.Claims.(*AgentLoginClaims)
if !ok {
return TokenNotValid, ""
}
// 校验token
key := fmt.Sprintf(rediskey.AgentLoginUserToken, claims.AgentId)
appToken, _ := helper.DefaultRedis.GetString(key)
if len(appToken) == 0 {
return TokenExpire, ""
}
if appToken != tokenStr {
return TokenExpire, ""
}
return TokenSuccess, strings.Join([]string{utility.IntToString(claims.AgentId), utility.IntToString(claims.UserId),
claims.Name, claims.Email, claims.IP}, ",")
}
// GetLoginAgentJwt 解析代理商登入信息
func GetLoginAgentJwt(tokenStr string) AgentLoginJwt {
if len(tokenStr) == 0 {
return AgentLoginJwt{}
}
tokenArr := strings.Split(tokenStr, ",")
arrLen := len(tokenArr)
item := AgentLoginJwt{
AgentId: utility.StringAsInteger(tokenArr[0]),
}
if arrLen > 1 {
item.UserId = utility.StringAsInteger(tokenArr[1])
}
if arrLen > 2 {
item.Name = tokenArr[2]
}
if arrLen > 3 {
item.Email = tokenArr[3]
}
if arrLen > 4 {
item.IP = tokenArr[4]
}
return item
}
// ========== Admin 专用 JWT ========== //
type AdminLogin struct {
UserID int `json:"user_id"`
Account string `json:"account"`
NickName string `json:"nickname"`
Phone string `json:"phone"`
Email string `json:"email"`
IP string `json:"ip"`
}
type AdminLoginClaims struct {
AdminLogin
jwt.RegisteredClaims //StandardClaims
}
var AdminSignedKey = []byte("adm23inTOKexKey:237") // Admin 签名 Key
const AdminTokenIssue = "tokexAdmin" // Admin 签发人
// GenerateAdminLoginToken 生成管理员登录 Token
func GenerateAdminLoginToken(admin AdminLogin, expires time.Duration) string {
exp := time.Now().Add(expires)
claims := AdminLoginClaims{
admin,
jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(exp), // 过期时间
Issuer: AdminTokenIssue, // 签发人
},
}
// 使用指定的签名方法创建签名对象
jwtToken, err := jwt.NewWithClaims(jwt.SigningMethodHS256, claims).SignedString(AdminSignedKey)
if err != nil {
log.Error("获取 jwtToken 失败:", zap.Error(err))
}
return jwtToken
}
// ParseAdminLoginToken 解析管理员登录 Token
func ParseAdminLoginToken(jwtToken string) (pass bool, adminLogin AdminLoginClaims) {
// 解析 jwtToken
token, err := jwt.ParseWithClaims(jwtToken, &AdminLoginClaims{}, func(token *jwt.Token) (i interface{}, err error) {
return AdminSignedKey, nil
})
if err != nil {
log.Error("解析 jwtToken 失败:", zap.Error(err))
return false, adminLogin
}
// 判断是否验证通过,并将 Claims => AdminLoginClaims
if claims, pass := token.Claims.(*AdminLoginClaims); pass && token.Valid {
return pass, *claims
}
return false, adminLogin
}