mirror of
https://github.com/LiteyukiStudio/spage.git
synced 2025-07-15 10:31:15 +00:00
⚡
This commit is contained in:
0
config/config.example.yaml
Normal file
0
config/config.example.yaml
Normal file
93
config/config.go
Normal file
93
config/config.go
Normal file
@ -0,0 +1,93 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/spf13/viper"
|
||||
)
|
||||
|
||||
var (
|
||||
ServerPort string
|
||||
Mode string
|
||||
JwtSecret string
|
||||
|
||||
//MessageSavingDays = 30 // 消息在数据库保存时间,单位天
|
||||
//MessageHangingSeconds = 10 // 消息挂起时间,单位秒
|
||||
//MessageResponseTimeout = 60 // 长轮询消息响应超时时间,单位秒
|
||||
|
||||
// CommitHash 构件时注入的git commit hash
|
||||
CommitHash = "develop" // git commit hash 构建时注入
|
||||
BuildTime = "0000-00-00 00:00:00" // 构建时间
|
||||
|
||||
)
|
||||
|
||||
func init() {
|
||||
// 设置配置文件路径
|
||||
viper.AddConfigPath(".")
|
||||
viper.SetConfigName("config")
|
||||
viper.SetConfigType("yaml")
|
||||
// 读取配置文件
|
||||
if err := viper.ReadInConfig(); err != nil {
|
||||
var configFileNotFoundError viper.ConfigFileNotFoundError
|
||||
if errors.As(err, &configFileNotFoundError) {
|
||||
panic(fmt.Errorf("Fatal error config file: %s \n", err))
|
||||
}
|
||||
}
|
||||
// 初始化配置常量
|
||||
ServerPort = GetString("server.port", "8888")
|
||||
JwtSecret = GetString("jwtSecret", "none-secret")
|
||||
logrus.Info("配置初始化成功")
|
||||
}
|
||||
|
||||
func Get[T any](key string, defaultValue T) T {
|
||||
if !viper.IsSet(key) {
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
value := viper.Get(key)
|
||||
if v, ok := value.(T); ok {
|
||||
return v
|
||||
}
|
||||
return defaultValue
|
||||
}
|
||||
|
||||
// GetString 返回配置项的字符串值
|
||||
func GetString(key string, defaultValue ...string) string {
|
||||
if len(defaultValue) > 0 {
|
||||
return Get(key, defaultValue[0])
|
||||
}
|
||||
return viper.GetString(key)
|
||||
}
|
||||
|
||||
// GetInt 返回配置项的整数值
|
||||
func GetInt(key string, defaultValue ...int) int {
|
||||
if len(defaultValue) > 0 {
|
||||
return Get(key, defaultValue[0])
|
||||
}
|
||||
return viper.GetInt(key)
|
||||
}
|
||||
|
||||
// GetBool 返回配置项的布尔值
|
||||
func GetBool(key string, defaultValue ...bool) bool {
|
||||
if len(defaultValue) > 0 {
|
||||
return Get(key, defaultValue[0])
|
||||
}
|
||||
return viper.GetBool(key)
|
||||
}
|
||||
|
||||
// GetFloat64 返回配置项的浮点数值
|
||||
func GetFloat64(key string, defaultValue ...float64) float64 {
|
||||
if len(defaultValue) > 0 {
|
||||
return Get(key, defaultValue[0])
|
||||
}
|
||||
return viper.GetFloat64(key)
|
||||
}
|
||||
|
||||
// GetStringSlice 返回配置项的字符串切片值
|
||||
func GetStringSlice(key string, defaultValue ...[]string) []string {
|
||||
if len(defaultValue) > 0 {
|
||||
return Get(key, defaultValue[0])
|
||||
}
|
||||
return viper.GetStringSlice(key)
|
||||
}
|
20
middle/auth.go
Normal file
20
middle/auth.go
Normal file
@ -0,0 +1,20 @@
|
||||
package middle
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/LiteyukiStudio/spage/resps"
|
||||
"github.com/cloudwego/hertz/pkg/app"
|
||||
)
|
||||
|
||||
type Auth struct{}
|
||||
|
||||
func (Auth) AuthToken() func(context.Context, *app.RequestContext) {
|
||||
return func(ctx context.Context, c *app.RequestContext) {
|
||||
token := string(c.GetHeader("Authorization"))
|
||||
if token == "" {
|
||||
resps.BadRequest(c, "Token is required")
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
package models
|
||||
|
49
resps/resps.go
Normal file
49
resps/resps.go
Normal file
@ -0,0 +1,49 @@
|
||||
package resps
|
||||
|
||||
import "github.com/cloudwego/hertz/pkg/app"
|
||||
|
||||
func Custom(c *app.RequestContext, code int, message string, data ...map[string]any) {
|
||||
if len(data) == 0 {
|
||||
data = append(data, map[string]any{})
|
||||
}
|
||||
data[0]["message"] = message
|
||||
c.JSON(code, data[0])
|
||||
}
|
||||
|
||||
// 2xx
|
||||
|
||||
func Ok(c *app.RequestContext, message string, data ...map[string]any) {
|
||||
if len(data) == 0 {
|
||||
data = append(data, map[string]any{})
|
||||
}
|
||||
data[0]["message"] = message
|
||||
c.JSON(200, data[0])
|
||||
}
|
||||
|
||||
// 4xx
|
||||
|
||||
func BadRequest(c *app.RequestContext, message string) {
|
||||
c.JSON(400, map[string]string{"message": message})
|
||||
}
|
||||
|
||||
func Unauthorized(c *app.RequestContext, message string) {
|
||||
c.JSON(401, map[string]string{"message": message})
|
||||
}
|
||||
|
||||
func Forbidden(c *app.RequestContext, message string, err error) {
|
||||
c.JSON(403, map[string]string{"message": message})
|
||||
}
|
||||
|
||||
func NotFound(c *app.RequestContext, message string) {
|
||||
c.JSON(404, map[string]string{"message": message})
|
||||
}
|
||||
|
||||
// 5xx
|
||||
|
||||
func InternalServerError(c *app.RequestContext, message string) {
|
||||
c.JSON(500, map[string]string{"message": message})
|
||||
}
|
||||
|
||||
func ServiceUnavailable(c *app.RequestContext, message string) {
|
||||
c.JSON(503, map[string]string{"message": message})
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package router
|
||||
|
||||
import (
|
||||
"context"
|
||||
"github.com/LiteyukiStudio/spage/config"
|
||||
"github.com/cloudwego/hertz/pkg/app"
|
||||
"github.com/cloudwego/hertz/pkg/app/server"
|
||||
"github.com/cloudwego/hertz/pkg/common/utils"
|
||||
)
|
||||
|
||||
//var H *server.Hertz
|
||||
|
||||
func Run() error {
|
||||
// 运行路由
|
||||
H := server.New(server.WithHostPorts(":" + config.ServerPort))
|
||||
H.GET("/", func(ctx context.Context, c *app.RequestContext) {
|
||||
c.JSON(200, utils.H{"message": "Hello World"})
|
||||
})
|
||||
|
||||
apiV1 := H.Group("/api/v1")
|
||||
{
|
||||
userGroup := apiV1.Group("/user")
|
||||
_ = userGroup
|
||||
}
|
||||
|
||||
// 运行服务
|
||||
if config.Mode == "dev" {
|
||||
err := H.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
} else {
|
||||
H.Spin()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
@ -0,0 +1 @@
|
||||
package rpc
|
||||
|
@ -0,0 +1 @@
|
||||
package store
|
||||
|
6
utils/auth/auth.go
Normal file
6
utils/auth/auth.go
Normal file
@ -0,0 +1,6 @@
|
||||
package auth
|
||||
|
||||
type UtilsType struct {
|
||||
}
|
||||
|
||||
var Auth = UtilsType{}
|
32
utils/auth/password.go
Normal file
32
utils/auth/password.go
Normal file
@ -0,0 +1,32 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
// HashPassword 密码哈希函数
|
||||
func (u *UtilsType) HashPassword(password string, salt string) (string, error) {
|
||||
saltedPassword := Auth.addSalt(password, salt)
|
||||
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(saltedPassword), bcrypt.DefaultCost)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
return string(hashedPassword), nil
|
||||
}
|
||||
|
||||
// VerifyPassword 验证密码
|
||||
func (u *UtilsType) VerifyPassword(password string, hash string, salt string) bool {
|
||||
saltedPassword := Auth.addSalt(password, salt)
|
||||
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(saltedPassword))
|
||||
return err == nil
|
||||
}
|
||||
|
||||
// addSalt 加盐函数
|
||||
func (u *UtilsType) addSalt(password string, salt string) string {
|
||||
combined := password + salt
|
||||
hash := sha256.New()
|
||||
hash.Write([]byte(combined))
|
||||
return hex.EncodeToString(hash.Sum(nil))
|
||||
}
|
51
utils/auth/token.go
Normal file
51
utils/auth/token.go
Normal file
@ -0,0 +1,51 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
"github.com/LiteyukiStudio/spage/config"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TokenSecret is the secret key used to sign the JWT tokens
|
||||
var TokenSecret = config.JwtSecret
|
||||
|
||||
// Claims defines the structure of JWT claims
|
||||
type Claims struct {
|
||||
jwt.RegisteredClaims
|
||||
UserID uint `json:"user_id"`
|
||||
}
|
||||
|
||||
// GenerateToken 为用户生成指定有效期的Token
|
||||
func (u *UtilsType) GenerateToken(userID uint, expireDuration time.Duration) (string, error) {
|
||||
claims := Claims{
|
||||
UserID: userID,
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(expireDuration)),
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
},
|
||||
}
|
||||
// 创建一个新的token对象
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
||||
// 签名token
|
||||
tokenString, err := token.SignedString([]byte(TokenSecret))
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return tokenString, nil
|
||||
}
|
||||
|
||||
// ValidateToken 验证token
|
||||
func (u *UtilsType) ValidateToken(tokenString string) (*Claims, error) {
|
||||
claims := &Claims{}
|
||||
token, err := jwt.ParseWithClaims(tokenString, claims, func(token *jwt.Token) (any, error) {
|
||||
return []byte(TokenSecret), nil
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if !token.Valid {
|
||||
return nil, jwt.ErrSignatureInvalid
|
||||
}
|
||||
return claims, nil
|
||||
}
|
3
utils/init.go
Normal file
3
utils/init.go
Normal file
@ -0,0 +1,3 @@
|
||||
package utils
|
||||
|
||||
type Utils struct{}
|
Reference in New Issue
Block a user