init: init refactor
This commit is contained in:
@@ -0,0 +1,10 @@
|
||||
package consts
|
||||
|
||||
// 表名前缀
|
||||
const TablePrefix = "sundynix_"
|
||||
|
||||
// Redis Key前缀
|
||||
const (
|
||||
RedisKeyJWTBlacklist = "jwt:blacklist:" // JWT黑名单
|
||||
RedisKeyUserToken = "user:token:" // 用户Token
|
||||
)
|
||||
@@ -0,0 +1,28 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"sundynix-micro-go/common/utils/uniqueid"
|
||||
"time"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
// BaseModel 基础模型,所有表的公共字段
|
||||
type BaseModel struct {
|
||||
ID string `gorm:"size:50;primaryKey" json:"id"`
|
||||
CreatedAt time.Time `json:"createdAt" gorm:"autoCreateTime"`
|
||||
UpdatedAt time.Time `json:"updatedAt" gorm:"autoCreateTime;autoUpdateTime"`
|
||||
DeletedAt gorm.DeletedAt `gorm:"index" json:"-"`
|
||||
}
|
||||
|
||||
// BeforeCreate 创建前自动生成雪花ID
|
||||
func (m *BaseModel) BeforeCreate(db *gorm.DB) (err error) {
|
||||
db.Statement.SetColumn("id", uniqueid.GenerateID())
|
||||
return
|
||||
}
|
||||
|
||||
// BeforeUpdate 更新前自动更新时间
|
||||
func (m *BaseModel) BeforeUpdate(db *gorm.DB) (err error) {
|
||||
db.Statement.SetColumn("updated_at", time.Now())
|
||||
return
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
package response
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
// Body 统一响应体
|
||||
type Body struct {
|
||||
Code int `json:"code"`
|
||||
Msg string `json:"msg"`
|
||||
Data interface{} `json:"data,omitempty"`
|
||||
}
|
||||
|
||||
func writeJSON(w http.ResponseWriter, body *Body) {
|
||||
w.Header().Set("Content-Type", "application/json; charset=utf-8")
|
||||
w.WriteHeader(http.StatusOK)
|
||||
_ = json.NewEncoder(w).Encode(body)
|
||||
}
|
||||
|
||||
// OkWithData 成功响应(带数据)
|
||||
func OkWithData(w http.ResponseWriter, data interface{}) {
|
||||
writeJSON(w, &Body{Code: 200, Msg: "success", Data: data})
|
||||
}
|
||||
|
||||
// Ok 成功响应(无数据)
|
||||
func Ok(w http.ResponseWriter) {
|
||||
writeJSON(w, &Body{Code: 200, Msg: "success"})
|
||||
}
|
||||
|
||||
// OkWithMsg 成功响应(自定义消息)
|
||||
func OkWithMsg(w http.ResponseWriter, msg string) {
|
||||
writeJSON(w, &Body{Code: 200, Msg: msg})
|
||||
}
|
||||
|
||||
// Fail 失败响应
|
||||
func Fail(w http.ResponseWriter, msg string) {
|
||||
writeJSON(w, &Body{Code: 400, Msg: msg})
|
||||
}
|
||||
|
||||
// FailWithCode 失败响应(自定义错误码)
|
||||
func FailWithCode(w http.ResponseWriter, code int, msg string) {
|
||||
writeJSON(w, &Body{Code: code, Msg: msg})
|
||||
}
|
||||
|
||||
// NoAuth 未授权响应
|
||||
func NoAuth(w http.ResponseWriter, msg string) {
|
||||
writeJSON(w, &Body{Code: 401, Msg: msg})
|
||||
}
|
||||
|
||||
// PageResult 分页结果
|
||||
type PageResult struct {
|
||||
List interface{} `json:"list"`
|
||||
Total int64 `json:"total"`
|
||||
Current int `json:"current"`
|
||||
Size int `json:"size"`
|
||||
}
|
||||
|
||||
// OkWithPage 分页成功响应
|
||||
func OkWithPage(w http.ResponseWriter, list interface{}, total int64, current, size int) {
|
||||
OkWithData(w, PageResult{
|
||||
List: list,
|
||||
Total: total,
|
||||
Current: current,
|
||||
Size: size,
|
||||
})
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package hash
|
||||
|
||||
import (
|
||||
"crypto/md5"
|
||||
"encoding/hex"
|
||||
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// BcryptHash 使用bcrypt对密码进行加密
|
||||
func BcryptHash(password string) string {
|
||||
bytes, _ := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||
return string(bytes)
|
||||
}
|
||||
|
||||
// BcryptCheck 对比明文密码和数据库的哈希值
|
||||
func BcryptCheck(password, hash string) bool {
|
||||
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// MD5 计算MD5哈希值
|
||||
func MD5(str []byte) string {
|
||||
h := md5.New()
|
||||
h.Write(str)
|
||||
return hex.EncodeToString(h.Sum(nil))
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package jwt
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
jwtv5 "github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
var (
|
||||
ErrTokenValid = errors.New("未知错误")
|
||||
ErrTokenExpired = errors.New("token已过期")
|
||||
ErrTokenNotValidYet = errors.New("token尚未激活")
|
||||
ErrTokenMalformed = errors.New("这不是一个token")
|
||||
ErrTokenSignatureInvalid = errors.New("无效签名")
|
||||
ErrTokenInvalid = errors.New("无法处理此token")
|
||||
)
|
||||
|
||||
// BaseClaims 基础Claims
|
||||
type BaseClaims struct {
|
||||
ID string `json:"id"`
|
||||
Account string `json:"account"`
|
||||
}
|
||||
|
||||
// CustomClaims 自定义Claims
|
||||
type CustomClaims struct {
|
||||
BaseClaims
|
||||
BufferTime int64 `json:"bufferTime"`
|
||||
jwtv5.RegisteredClaims
|
||||
}
|
||||
|
||||
// JWT JWT工具
|
||||
type JWT struct {
|
||||
SigningKey []byte
|
||||
}
|
||||
|
||||
// NewJWT 创建JWT实例
|
||||
func NewJWT(signingKey string) *JWT {
|
||||
return &JWT{
|
||||
SigningKey: []byte(signingKey),
|
||||
}
|
||||
}
|
||||
|
||||
// CreateClaims 创建Claims
|
||||
func (j *JWT) CreateClaims(baseClaims BaseClaims, bufferTime, expiresTime time.Duration, issuer string) CustomClaims {
|
||||
return CustomClaims{
|
||||
BaseClaims: baseClaims,
|
||||
BufferTime: int64(bufferTime / time.Second),
|
||||
RegisteredClaims: jwtv5.RegisteredClaims{
|
||||
Audience: jwtv5.ClaimStrings{"sundynix"},
|
||||
NotBefore: jwtv5.NewNumericDate(time.Now().Add(-1000)),
|
||||
ExpiresAt: jwtv5.NewNumericDate(time.Now().Add(expiresTime)),
|
||||
Issuer: issuer,
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
// CreateToken 创建token
|
||||
func (j *JWT) CreateToken(claims CustomClaims) (string, error) {
|
||||
token := jwtv5.NewWithClaims(jwtv5.SigningMethodHS256, claims)
|
||||
return token.SignedString(j.SigningKey)
|
||||
}
|
||||
|
||||
// ParseToken 解析token
|
||||
func (j *JWT) ParseToken(tokenString string) (*CustomClaims, error) {
|
||||
token, err := jwtv5.ParseWithClaims(tokenString, &CustomClaims{}, func(token *jwtv5.Token) (interface{}, error) {
|
||||
return j.SigningKey, nil
|
||||
})
|
||||
if err != nil {
|
||||
switch {
|
||||
case errors.Is(err, jwtv5.ErrTokenExpired):
|
||||
return nil, ErrTokenExpired
|
||||
case errors.Is(err, jwtv5.ErrTokenNotValidYet):
|
||||
return nil, ErrTokenNotValidYet
|
||||
case errors.Is(err, jwtv5.ErrTokenMalformed):
|
||||
return nil, ErrTokenMalformed
|
||||
case errors.Is(err, jwtv5.ErrTokenSignatureInvalid):
|
||||
return nil, ErrTokenSignatureInvalid
|
||||
default:
|
||||
return nil, ErrTokenInvalid
|
||||
}
|
||||
}
|
||||
if token != nil {
|
||||
if claims, ok := token.Claims.(*CustomClaims); ok && token.Valid {
|
||||
return claims, nil
|
||||
}
|
||||
}
|
||||
return nil, ErrTokenInvalid
|
||||
}
|
||||
|
||||
// GetTokenFromHeader 从Authorization头中提取token
|
||||
func GetTokenFromHeader(authHeader string) string {
|
||||
if len(authHeader) > 7 && authHeader[:7] == "Bearer " {
|
||||
return authHeader[7:]
|
||||
}
|
||||
return authHeader
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package uniqueid
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"fmt"
|
||||
"math/big"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
// GenerateID 生成UUID v1作为主键
|
||||
func GenerateID() string {
|
||||
uuidV1, err := uuid.NewUUID()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return uuidV1.String()
|
||||
}
|
||||
|
||||
// GenerateName 生成随机用户名
|
||||
func GenerateName(prefix string) string {
|
||||
str := uuid.New().String()
|
||||
return prefix + str[6:12]
|
||||
}
|
||||
|
||||
// GenerateRandomCode 生成随机码(如邀请码)
|
||||
func GenerateRandomCode(length int) string {
|
||||
const charset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||
var sb strings.Builder
|
||||
for i := 0; i < length; i++ {
|
||||
n, _ := rand.Int(rand.Reader, big.NewInt(int64(len(charset))))
|
||||
sb.WriteByte(charset[n.Int64()])
|
||||
}
|
||||
return sb.String()
|
||||
}
|
||||
|
||||
// GenCodeKey 生成邀请码的Redis Key
|
||||
func GenCodeKey(userID string) string {
|
||||
return fmt.Sprintf("code:%s", userID)
|
||||
}
|
||||
|
||||
// GenOrderNo 生成订单号
|
||||
func GenOrderNo() string {
|
||||
now := time.Now()
|
||||
timePart := now.Format("20060102150405")
|
||||
machineID := 1
|
||||
pid := now.Nanosecond() % 1000
|
||||
businessPart := fmt.Sprintf("%02d%03d%01d", machineID, pid, now.Second()%10)
|
||||
random1 := fmt.Sprintf("%04d", now.Nanosecond()%10000)
|
||||
random2 := fmt.Sprintf("%04d", (now.Nanosecond()/10000)%10000)
|
||||
return timePart + businessPart + random1 + random2
|
||||
}
|
||||
Reference in New Issue
Block a user