1
This commit is contained in:
88
pkg/cryptohelper/aeshelper/aes256.go
Normal file
88
pkg/cryptohelper/aeshelper/aes256.go
Normal file
@ -0,0 +1,88 @@
|
||||
package aeshelper
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/md5"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"io"
|
||||
)
|
||||
|
||||
// Encrypt text with the passphrase
|
||||
func Encrypt(text string, passphrase string) string {
|
||||
salt := make([]byte, 8)
|
||||
if _, err := io.ReadFull(rand.Reader, salt); err != nil {
|
||||
panic(err.Error())
|
||||
}
|
||||
|
||||
key, iv := DeriveKeyAndIv(passphrase, string(salt))
|
||||
|
||||
block, err := aes.NewCipher([]byte(key))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
pad := PKCS7Padding([]byte(text), block.BlockSize())
|
||||
ecb := cipher.NewCBCEncrypter(block, []byte(iv))
|
||||
encrypted := make([]byte, len(pad))
|
||||
ecb.CryptBlocks(encrypted, pad)
|
||||
|
||||
return base64.StdEncoding.EncodeToString([]byte("Salted__" + string(salt) + string(encrypted)))
|
||||
}
|
||||
|
||||
// Decrypt encrypted text with the passphrase
|
||||
func Decrypt(encrypted string, passphrase string) string {
|
||||
ct, _ := base64.StdEncoding.DecodeString(encrypted)
|
||||
if len(ct) < 16 || string(ct[:8]) != "Salted__" {
|
||||
return ""
|
||||
}
|
||||
|
||||
salt := ct[8:16]
|
||||
ct = ct[16:]
|
||||
key, iv := DeriveKeyAndIv(passphrase, string(salt))
|
||||
|
||||
block, err := aes.NewCipher([]byte(key))
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
cbc := cipher.NewCBCDecrypter(block, []byte(iv))
|
||||
dst := make([]byte, len(ct))
|
||||
cbc.CryptBlocks(dst, ct)
|
||||
|
||||
return string(PKCS7Trimming(dst))
|
||||
}
|
||||
|
||||
// PKCS7Padding PKCS7Padding
|
||||
func PKCS7Padding(ciphertext []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(ciphertext)%blockSize
|
||||
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(ciphertext, padtext...)
|
||||
}
|
||||
|
||||
// PKCS7Trimming PKCS7Trimming
|
||||
func PKCS7Trimming(encrypt []byte) []byte {
|
||||
padding := encrypt[len(encrypt)-1]
|
||||
return encrypt[:len(encrypt)-int(padding)]
|
||||
}
|
||||
|
||||
// DeriveKeyAndIv DeriveKeyAndIv
|
||||
func DeriveKeyAndIv(passphrase string, salt string) (string, string) {
|
||||
salted := ""
|
||||
dI := ""
|
||||
|
||||
for len(salted) < 48 {
|
||||
md := md5.New()
|
||||
md.Write([]byte(dI + passphrase + salt))
|
||||
dM := md.Sum(nil)
|
||||
dI = string(dM[:16])
|
||||
salted = salted + dI
|
||||
}
|
||||
|
||||
key := salted[0:32]
|
||||
iv := salted[32:48]
|
||||
|
||||
return key, iv
|
||||
}
|
||||
107
pkg/cryptohelper/aeshelper/aeshelper.go
Normal file
107
pkg/cryptohelper/aeshelper/aeshelper.go
Normal file
@ -0,0 +1,107 @@
|
||||
package aeshelper
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"encoding/base64"
|
||||
"encoding/hex"
|
||||
"github.com/forgoer/openssl"
|
||||
)
|
||||
|
||||
const (
|
||||
sKey = "ptQJqRKxICCTeo6w" // "dde4b1f8a9e6b814"
|
||||
ivParameter = "O3vZvOJSnQDP9hKT" // "dde4b1f8a9e6b814"
|
||||
|
||||
)
|
||||
|
||||
// PswEncrypt 加密
|
||||
func PswEncrypt(src string) (string, error) {
|
||||
key := []byte(sKey)
|
||||
iv := []byte(ivParameter)
|
||||
result, err := Aes128Encrypt([]byte(src), key, iv)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return base64.RawStdEncoding.EncodeToString(result), nil
|
||||
}
|
||||
|
||||
// PswDecrypt 解密
|
||||
func PswDecrypt(src string) (string, error) {
|
||||
key := []byte(sKey)
|
||||
iv := []byte(ivParameter)
|
||||
var result []byte
|
||||
var err error
|
||||
result, err = base64.StdEncoding.DecodeString(src)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
origData, err := Aes128Decrypt(result, key, iv)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(origData), nil
|
||||
}
|
||||
|
||||
func Aes128Encrypt(origData, key []byte, IV []byte) ([]byte, error) {
|
||||
if key == nil || len(key) != 16 {
|
||||
return nil, nil
|
||||
}
|
||||
if IV != nil && len(IV) != 16 {
|
||||
return nil, nil
|
||||
}
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockSize := block.BlockSize()
|
||||
origData = PKCS5Padding(origData, blockSize)
|
||||
blockMode := cipher.NewCBCEncrypter(block, IV[:blockSize])
|
||||
crypted := make([]byte, len(origData))
|
||||
// 根据CryptBlocks方法的说明,如下方式初始化crypted也可以
|
||||
blockMode.CryptBlocks(crypted, origData)
|
||||
return crypted, nil
|
||||
}
|
||||
func Aes128Decrypt(crypted, key []byte, IV []byte) ([]byte, error) {
|
||||
if key == nil || len(key) != 16 {
|
||||
return nil, nil
|
||||
}
|
||||
if IV != nil && len(IV) != 16 {
|
||||
return nil, nil
|
||||
}
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
blockSize := block.BlockSize()
|
||||
blockMode := cipher.NewCBCDecrypter(block, IV[:blockSize])
|
||||
origData := make([]byte, len(crypted))
|
||||
blockMode.CryptBlocks(origData, crypted)
|
||||
origData = PKCS5UnPadding(origData)
|
||||
return origData, nil
|
||||
}
|
||||
func PKCS5Padding(ciphertext []byte, blockSize int) []byte {
|
||||
padding := blockSize - len(ciphertext)%blockSize
|
||||
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(ciphertext, padtext...)
|
||||
}
|
||||
func PKCS5UnPadding(origData []byte) []byte {
|
||||
length := len(origData)
|
||||
// 去掉最后一个字节 unpadding 次
|
||||
unpadding := int(origData[length-1])
|
||||
return origData[:(length - unpadding)]
|
||||
}
|
||||
|
||||
// 密码加密
|
||||
func AesEcbEncrypt(origData string) string {
|
||||
//加密
|
||||
dst, _ := openssl.AesECBEncrypt([]byte(origData), []byte(sKey), openssl.PKCS7_PADDING)
|
||||
return hex.EncodeToString(dst)
|
||||
}
|
||||
|
||||
// 密码解密
|
||||
func AesEcbDecrypt(origData string) string {
|
||||
value, _ := hex.DecodeString(origData)
|
||||
dst, _ := openssl.AesECBDecrypt(value, []byte(sKey), openssl.PKCS7_PADDING)
|
||||
return string(dst)
|
||||
}
|
||||
65
pkg/cryptohelper/aeshelper/aeshelper_test.go
Normal file
65
pkg/cryptohelper/aeshelper/aeshelper_test.go
Normal file
@ -0,0 +1,65 @@
|
||||
package aeshelper
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// 测试加密解密
|
||||
func Test_EnDe(t *testing.T) {
|
||||
a := `asg`
|
||||
b := Encrypt(a, `code_verify_success`)
|
||||
c := Decrypt(b, `code_verify_success`)
|
||||
fmt.Println(`原始为`, a)
|
||||
fmt.Println(`加密后`, b)
|
||||
fmt.Println(`解密后`, c)
|
||||
}
|
||||
func TestAesEcbEncrypt(t *testing.T) {
|
||||
//aes := AesEcbEncrypt("123456")
|
||||
aes := AesEcbEncrypt(fmt.Sprintf("%v_%v", time.Now().Unix(), 1332355333))
|
||||
dst := AesEcbDecrypt(aes)
|
||||
fmt.Println(aes)
|
||||
fmt.Println(dst)
|
||||
}
|
||||
|
||||
// TODO:需要加密的接口
|
||||
/**
|
||||
1.合约下单接口 /api/futures/trade/order
|
||||
2.合约撤单 /api/futures/trade/cancelorder
|
||||
3.调整保证金 /api/futures/trade/adjustmargin
|
||||
4.变换逐全仓模式 /api/futures/trade/marginType
|
||||
5.更改持仓模式(方向) /api/futures/trade/positionSide/dual
|
||||
6.资产划转 /api/futures/transfer
|
||||
*/
|
||||
func TestAesEcbEncryptOrder(t *testing.T) {
|
||||
data := addFutOrderReq{
|
||||
OrderType: 1,
|
||||
BuyType: 3,
|
||||
TriggerDecide: 3,
|
||||
IsReduce: 2,
|
||||
Coin: "asdf",
|
||||
Price: "333.23",
|
||||
Num: "23.20",
|
||||
TriggerPrice: "1.023",
|
||||
PositionSide: "long",
|
||||
}
|
||||
b, _ := json.Marshal(data)
|
||||
aes := AesEcbEncrypt(string(b))
|
||||
dst := AesEcbDecrypt(aes)
|
||||
fmt.Println(aes)
|
||||
fmt.Println(dst)
|
||||
}
|
||||
|
||||
type addFutOrderReq struct {
|
||||
OrderType int `json:"order_type"` // 订单类型:1限价,2限价止盈止损,3市价,4市价止盈止损,5强平委托(就是限价委托)
|
||||
BuyType int `json:"buy_type"` // 买卖类型:1买,2卖
|
||||
TriggerDecide int `json:"trigger_decide"` // 触发条件 1按最新成交价格算,2按标记价格算
|
||||
IsReduce int `json:"is_reduce"` // 1是只减仓位(点击仓位列表中的平仓按钮),0正常
|
||||
Coin string `json:"coin"` // 交易币
|
||||
Price string `json:"price"` // 下单价格(限价+止盈止损时,该字段必填)
|
||||
Num string `json:"num"` // 下单数量(市价时该字段必填)
|
||||
TriggerPrice string `json:"trigger_price"` // 触发价格
|
||||
PositionSide string `json:"position_side"` // 持仓方向,单向持仓模式下可填both;在双向持仓模式下必填,且仅可选择 long 或 short
|
||||
}
|
||||
94
pkg/cryptohelper/aeshelper/aesoldhelper/aesoldhelper.go
Normal file
94
pkg/cryptohelper/aeshelper/aesoldhelper/aesoldhelper.go
Normal file
@ -0,0 +1,94 @@
|
||||
package aesoldhelper
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/aes"
|
||||
"crypto/cipher"
|
||||
"crypto/rand"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"io"
|
||||
"strings"
|
||||
)
|
||||
|
||||
func addBase64Padding(value string) string {
|
||||
m := len(value) % 4
|
||||
if m != 0 {
|
||||
value += strings.Repeat("=", 4-m)
|
||||
}
|
||||
|
||||
return value
|
||||
}
|
||||
|
||||
func removeBase64Padding(value string) string {
|
||||
return strings.Replace(value, "=", "", -1)
|
||||
}
|
||||
|
||||
// Pad Pad
|
||||
func Pad(src []byte) []byte {
|
||||
padding := aes.BlockSize - len(src)%aes.BlockSize
|
||||
padtext := bytes.Repeat([]byte{byte(padding)}, padding)
|
||||
return append(src, padtext...)
|
||||
}
|
||||
|
||||
// Unpad Unpad
|
||||
func Unpad(src []byte) ([]byte, error) {
|
||||
length := len(src)
|
||||
unpadding := int(src[length-1])
|
||||
|
||||
if unpadding > length {
|
||||
return nil, errors.New("unpad error. This could happen when incorrect encryption key is used")
|
||||
}
|
||||
|
||||
return src[:(length - unpadding)], nil
|
||||
}
|
||||
|
||||
// AesEncrypt AesEncrypt
|
||||
func AesEncrypt(key []byte, text string) (string, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
msg := Pad([]byte(text))
|
||||
ciphertext := make([]byte, aes.BlockSize+len(msg))
|
||||
iv := ciphertext[:aes.BlockSize]
|
||||
if _, err := io.ReadFull(rand.Reader, iv); err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
cfb := cipher.NewCFBEncrypter(block, iv)
|
||||
cfb.XORKeyStream(ciphertext[aes.BlockSize:], []byte(msg))
|
||||
finalMsg := removeBase64Padding(base64.URLEncoding.EncodeToString(ciphertext))
|
||||
return finalMsg, nil
|
||||
}
|
||||
|
||||
// AesDecrypt AesDecrypt
|
||||
func AesDecrypt(key []byte, text string) (string, error) {
|
||||
block, err := aes.NewCipher(key)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
decodedMsg, err := base64.URLEncoding.DecodeString(addBase64Padding(text))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if (len(decodedMsg) % aes.BlockSize) != 0 {
|
||||
return "", errors.New("blocksize must be multipe of decoded message length")
|
||||
}
|
||||
|
||||
iv := decodedMsg[:aes.BlockSize]
|
||||
msg := decodedMsg[aes.BlockSize:]
|
||||
|
||||
cfb := cipher.NewCFBDecrypter(block, iv)
|
||||
cfb.XORKeyStream(msg, msg)
|
||||
|
||||
unpadMsg, err := Unpad(msg)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return string(unpadMsg), nil
|
||||
}
|
||||
19
pkg/cryptohelper/aeshelper/apikey.go
Normal file
19
pkg/cryptohelper/aeshelper/apikey.go
Normal file
@ -0,0 +1,19 @@
|
||||
package aeshelper
|
||||
|
||||
var (
|
||||
apiaeskey = "9jxFTkydwCJsmIA1TUrv"
|
||||
)
|
||||
|
||||
// EncryptApi 加密apikey
|
||||
func EncryptApi(apikey, secretkey string) (apikeyen, secrekeyen string) {
|
||||
apikeyen = Encrypt(apikey, apiaeskey)
|
||||
secrekeyen = Encrypt(secretkey, apiaeskey)
|
||||
return apikeyen, secrekeyen
|
||||
}
|
||||
|
||||
// DecryptApi 解密apikey
|
||||
func DecryptApi(apikeyen, secrekeyen string) (apikey, secrekey string) {
|
||||
apikey = Decrypt(apikeyen, apiaeskey)
|
||||
secrekey = Decrypt(secrekeyen, apiaeskey)
|
||||
return apikey, secrekey
|
||||
}
|
||||
133
pkg/cryptohelper/inttostring/Inttoostr.go
Normal file
133
pkg/cryptohelper/inttostring/Inttoostr.go
Normal file
@ -0,0 +1,133 @@
|
||||
package inttostring
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/rand"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// IntToStr 用于将数字映射为字符串 例如 用户id-->邀请码
|
||||
type IntToStr struct {
|
||||
SALT int // 随意取一个数值
|
||||
Len int // 邀请码长度
|
||||
PRIME2 byte // 与邀请码长度 8 互质
|
||||
AlphanumericSet []rune
|
||||
PRIME1 int // 与字符集长度 36 互质
|
||||
}
|
||||
|
||||
var (
|
||||
Invite = NewInvite() // 邀请码
|
||||
)
|
||||
|
||||
// NewInvite 邀请码
|
||||
func NewInvite() *IntToStr {
|
||||
return &IntToStr{
|
||||
SALT: 15151239, // 随意取一个数值
|
||||
Len: 8, // 邀请码长度
|
||||
PRIME2: 3, // 与邀请码长度 Len 互质
|
||||
AlphanumericSet: []rune{
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
||||
'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
|
||||
'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
|
||||
}, // 邀请码长度
|
||||
PRIME1: 5, // 与字符集长度 36 互质
|
||||
}
|
||||
}
|
||||
|
||||
func (in IntToStr) DeCode(codeStr string) int {
|
||||
code := make([]rune, 0, in.Len)
|
||||
var key rune = 0
|
||||
// 还原k
|
||||
for i := 0; i < in.Len; i++ {
|
||||
for k, v := range in.AlphanumericSet {
|
||||
if v == rune(codeStr[i]) {
|
||||
key = rune(k)
|
||||
break
|
||||
}
|
||||
}
|
||||
code = append(code, key)
|
||||
}
|
||||
code2 := make([]rune, 0, in.Len)
|
||||
// 还原顺序
|
||||
for i := 0; i < in.Len; i++ {
|
||||
idx := i * int(in.PRIME2) % in.Len
|
||||
code2 = append(code2, code[idx])
|
||||
}
|
||||
|
||||
// 还原数字
|
||||
var x int
|
||||
for i := 0; i < in.Len; i++ {
|
||||
code2[i] = (code2[i] - rune(i)*code2[0]) % rune(len(in.AlphanumericSet))
|
||||
code2[i] = (code2[i] + rune(len(in.AlphanumericSet))) % rune(len(in.AlphanumericSet))
|
||||
place := math.Pow(float64(len(in.AlphanumericSet)), float64(i)) // 次方运算
|
||||
x += int(code2[i]) * int(place)
|
||||
}
|
||||
// 去盐 + 缩小
|
||||
x = (x - in.SALT) / in.PRIME1
|
||||
|
||||
return x
|
||||
}
|
||||
|
||||
func (in IntToStr) Encode(uid int) string {
|
||||
// 放大 + 加盐
|
||||
uid = uid*in.PRIME1 + in.SALT
|
||||
slIdx := make([]byte, in.Len)
|
||||
|
||||
// 扩散
|
||||
for i := 0; i < in.Len; i++ {
|
||||
slIdx[i] = byte(uid % len(in.AlphanumericSet)) // 转换进制 获取36进制的每一位值
|
||||
slIdx[i] = (slIdx[i] + byte(i)*slIdx[0]) % byte(len(in.AlphanumericSet)) // 其他位与个位加和再取余(让个位的变化影响到所有位)
|
||||
uid = uid / len(in.AlphanumericSet) // 相当于右移一位(62进制)
|
||||
}
|
||||
|
||||
var code []rune
|
||||
// 混淆
|
||||
for i := 0; i < in.Len; i++ {
|
||||
idx := (byte(i) * in.PRIME2) % byte(in.Len)
|
||||
code = append(code, in.AlphanumericSet[slIdx[idx]])
|
||||
}
|
||||
return string(code)
|
||||
}
|
||||
|
||||
const letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
const smsLetters = "0123456789"
|
||||
|
||||
// GenerateRandomString 生成指定长度的随机字符串
|
||||
func GenerateRandomString(n int) string {
|
||||
rand.Seed(time.Now().UnixNano()) // 初始化随机数种子
|
||||
result := make([]byte, n)
|
||||
for i := range result {
|
||||
result[i] = letters[rand.Intn(len(letters))]
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
// GenerateRandomSmsString 生成指定长度的随机字符串
|
||||
func GenerateRandomSmsString(n int) string {
|
||||
rand.Seed(time.Now().UnixNano()) // 初始化随机数种子
|
||||
result := make([]byte, n)
|
||||
for i := range result {
|
||||
result[i] = smsLetters[rand.Intn(len(smsLetters))]
|
||||
}
|
||||
return string(result)
|
||||
}
|
||||
|
||||
func EncryptString(s string, prefixLen, suffixLen int) string {
|
||||
length := len(s)
|
||||
|
||||
// 如果字符串长度不足,直接返回原字符串
|
||||
if length <= prefixLen+suffixLen {
|
||||
return s
|
||||
}
|
||||
|
||||
// 保留前 prefixLen 位和后 suffixLen 位
|
||||
prefix := s[:prefixLen]
|
||||
suffix := s[length-suffixLen:]
|
||||
|
||||
// 中间部分用 * 替换
|
||||
middle := strings.Repeat("*", 6)
|
||||
|
||||
// 拼接结果
|
||||
return prefix + middle + suffix
|
||||
}
|
||||
33
pkg/cryptohelper/inttostring/Inttoostr_test.go
Normal file
33
pkg/cryptohelper/inttostring/Inttoostr_test.go
Normal file
@ -0,0 +1,33 @@
|
||||
package inttostring
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
|
||||
func Test_a(t *testing.T) {
|
||||
a:=1156
|
||||
// b:=byte(a)
|
||||
fmt.Println(a%10)
|
||||
}
|
||||
// 加密解密
|
||||
func Test_EnDecode(t *testing.T) {
|
||||
uid := 6515461646
|
||||
Invi := NewInvite()
|
||||
encode := Invi.Encode(uid)
|
||||
DeCode := Invi.DeCode(encode)
|
||||
fmt.Println(`原始为`, uid)
|
||||
fmt.Println(`加密后`, encode)
|
||||
fmt.Println(`解密后`, DeCode)
|
||||
}
|
||||
|
||||
func Test_Invite(t *testing.T) {
|
||||
for uid := 0; uid < 10000000; uid++ {
|
||||
encode := Invite.Encode(uid)
|
||||
DeCode := Invite.DeCode(encode)
|
||||
if DeCode != uid {
|
||||
t.Fatal(`加密解密错误`, DeCode, uid)
|
||||
}
|
||||
}
|
||||
}
|
||||
295
pkg/cryptohelper/jwthelper/jwthelper.go
Normal file
295
pkg/cryptohelper/jwthelper/jwthelper.go
Normal file
@ -0,0 +1,295 @@
|
||||
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
|
||||
}
|
||||
17
pkg/cryptohelper/md5helper/md5helper.go
Normal file
17
pkg/cryptohelper/md5helper/md5helper.go
Normal file
@ -0,0 +1,17 @@
|
||||
package md5helper
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
)
|
||||
|
||||
// MD5 md5加密
|
||||
func MD5(input string) string {
|
||||
cc := md5.Sum([]byte(input))
|
||||
return hex.EncodeToString(cc[:])
|
||||
}
|
||||
|
||||
// MD52 md52次
|
||||
func MD52(input string) string {
|
||||
return MD5(MD5(input))
|
||||
}
|
||||
55
pkg/cryptohelper/md5helper/md5helper_test.go
Normal file
55
pkg/cryptohelper/md5helper/md5helper_test.go
Normal file
@ -0,0 +1,55 @@
|
||||
package md5helper
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestMD52(t *testing.T) {
|
||||
got := MD52("Qq123456")
|
||||
fmt.Println(got)
|
||||
}
|
||||
|
||||
func TestMD5(t *testing.T) {
|
||||
got := []byte("Qq123456")
|
||||
s := md5.New()
|
||||
s.Write(got)
|
||||
fmt.Println(hex.EncodeToString(s.Sum(nil)))
|
||||
|
||||
cc := md5.Sum(got)
|
||||
fmt.Println(hex.EncodeToString(cc[:]))
|
||||
|
||||
fmt.Printf("%x\n", md5.Sum(got))
|
||||
|
||||
}
|
||||
|
||||
// go test -bench=_QE_ -benchmem -run=^$
|
||||
func Benchmark_QE_1(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
input := `Qq123456`
|
||||
s := md5.New()
|
||||
s.Write([]byte(input))
|
||||
hex.EncodeToString(s.Sum(nil))
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_QE_2(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
input := `Qq123456`
|
||||
cc := md5.Sum([]byte(input))
|
||||
hex.EncodeToString(cc[:])
|
||||
}
|
||||
}
|
||||
|
||||
func Benchmark_QE_3(b *testing.B) {
|
||||
for i := 0; i < b.N; i++ {
|
||||
input := `Qq123456`
|
||||
fmt.Sprintf("%x\n", md5.Sum([]byte(input)))
|
||||
}
|
||||
}
|
||||
|
||||
// Benchmark_QE_1-6 6354160 189.8 ns/op 48 B/op 2 allocs/op
|
||||
// Benchmark_QE_2-6 7352328 162.9 ns/op 32 B/op 1 allocs/op
|
||||
// Benchmark_QE_3-6 3007480 396.9 ns/op 80 B/op 3 allocs/op
|
||||
Reference in New Issue
Block a user