update
This commit is contained in:
parent
c6e76da127
commit
70fa16c938
8
.history/config/config_20240925094043.go
Normal file
8
.history/config/config_20240925094043.go
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
const (
|
||||||
|
//日志文件路径
|
||||||
|
LogFilePath = "testfb.log"
|
||||||
|
//地址+端口
|
||||||
|
Port = ":3030"
|
||||||
|
)
|
||||||
29
.history/config/config_20240925155958.go
Normal file
29
.history/config/config_20240925155958.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gofiber/storage/redis/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
DBConnString string
|
||||||
|
RedisAddr string
|
||||||
|
JWTSecret string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() *Config {
|
||||||
|
return &Config{
|
||||||
|
DBConnString: "root:password@tcp(localhost:3306)/testfb?charset=utf8mb4&parseTime=True&loc=Local",
|
||||||
|
RedisAddr: "localhost:6379",
|
||||||
|
JWTSecret: "your-secret-key",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitRedis(addr string) *redis.Storage {
|
||||||
|
return redis.New(redis.Config{
|
||||||
|
Host: addr,
|
||||||
|
Port: 6379,
|
||||||
|
Username: "",
|
||||||
|
Password: "",
|
||||||
|
Database: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
29
.history/config/config_20240925160003.go
Normal file
29
.history/config/config_20240925160003.go
Normal file
@ -0,0 +1,29 @@
|
|||||||
|
package config
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gofiber/storage/redis/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
DBConnString string
|
||||||
|
RedisAddr string
|
||||||
|
JWTSecret string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() *Config {
|
||||||
|
return &Config{
|
||||||
|
DBConnString: "root:password@tcp(localhost:3306)/testfb?charset=utf8mb4&parseTime=True&loc=Local",
|
||||||
|
RedisAddr: "localhost:6379",
|
||||||
|
JWTSecret: "your-secret-key",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitRedis(addr string) *redis.Storage {
|
||||||
|
return redis.New(redis.Config{
|
||||||
|
Host: addr,
|
||||||
|
Port: 6379,
|
||||||
|
Username: "",
|
||||||
|
Password: "",
|
||||||
|
Database: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
0
.history/handlers/handlers_20240925160117.go
Normal file
0
.history/handlers/handlers_20240925160117.go
Normal file
102
.history/handlers/handlers_20240925160124.go
Normal file
102
.history/handlers/handlers_20240925160124.go
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/gofiber/storage/redis/v3"
|
||||||
|
"github.com/golang-jwt/jwt/v4"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"testfb/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Login(db *gorm.DB, redisClient *redis.Storage) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
var input struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.BodyParser(&input); err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid input"})
|
||||||
|
}
|
||||||
|
|
||||||
|
var user models.User
|
||||||
|
if err := db.Where("username = ?", input.Username).First(&user).Error; err != nil {
|
||||||
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid credentials"})
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := user.ComparePassword(input.Password); err != nil {
|
||||||
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid credentials"})
|
||||||
|
}
|
||||||
|
|
||||||
|
token := jwt.New(jwt.SigningMethodHS256)
|
||||||
|
claims := token.Claims.(jwt.MapClaims)
|
||||||
|
claims["user_id"] = user.ID
|
||||||
|
claims["exp"] = time.Now().Add(time.Hour * 24).Unix()
|
||||||
|
|
||||||
|
t, err := token.SignedString([]byte("your-secret-key"))
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Could not login"})
|
||||||
|
}
|
||||||
|
|
||||||
|
err = redisClient.Set(t, user.ID, 24*time.Hour)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Could not store token"})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(fiber.Map{"token": t})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCurrentUser(db *gorm.DB) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
userID := c.Locals("user_id").(uint)
|
||||||
|
|
||||||
|
var user models.User
|
||||||
|
if err := db.First(&user, userID).Error; err != nil {
|
||||||
|
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "User not found"})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateCurrentUser(db *gorm.DB) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
userID := c.Locals("user_id").(uint)
|
||||||
|
|
||||||
|
var input models.User
|
||||||
|
if err := c.BodyParser(&input); err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid input"})
|
||||||
|
}
|
||||||
|
|
||||||
|
var user models.User
|
||||||
|
if err := db.First(&user, userID).Error; err != nil {
|
||||||
|
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "User not found"})
|
||||||
|
}
|
||||||
|
|
||||||
|
user.Email = input.Email
|
||||||
|
user.Phone = input.Phone
|
||||||
|
|
||||||
|
if err := db.Save(&user).Error; err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Could not update user"})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUserByID(db *gorm.DB) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
id := c.Params("id")
|
||||||
|
|
||||||
|
var user models.User
|
||||||
|
if err := db.First(&user, id).Error; err != nil {
|
||||||
|
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "User not found"})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(user)
|
||||||
|
}
|
||||||
|
}
|
||||||
35
.history/main_20240925093717.go
Normal file
35
.history/main_20240925093717.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"testfb/config"
|
||||||
|
"testfb/routes"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/gofiber/fiber/v2/middleware/logger"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
//创建日志文件
|
||||||
|
f, err := os.OpenFile(config.LogFilePath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalln("日志文件创建失败:", err)
|
||||||
|
}
|
||||||
|
defer f.Close()
|
||||||
|
|
||||||
|
app := fiber.New()
|
||||||
|
|
||||||
|
app.Use(logger.New(logger.Config{
|
||||||
|
Output: f,
|
||||||
|
}))
|
||||||
|
|
||||||
|
//注册路由
|
||||||
|
routes.SetupRoutes(app)
|
||||||
|
// 启动服务
|
||||||
|
log.Println("服务启动成功,监听端口:", config.Port)
|
||||||
|
if err := app.Listen(config.Port); err != nil {
|
||||||
|
log.Fatalln("服务启动失败:", err)
|
||||||
|
}
|
||||||
|
}
|
||||||
61
.history/main_20240925155936.go
Normal file
61
.history/main_20240925155936.go
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/gofiber/fiber/v2/middleware/logger"
|
||||||
|
"gorm.io/driver/mysql"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"testfb/config"
|
||||||
|
"testfb/handlers"
|
||||||
|
"testfb/middleware"
|
||||||
|
"testfb/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
// Initialize configuration
|
||||||
|
cfg := config.New()
|
||||||
|
|
||||||
|
// Set up logging
|
||||||
|
logFile, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error opening log file: %v", err)
|
||||||
|
}
|
||||||
|
defer logFile.Close()
|
||||||
|
|
||||||
|
// Initialize database
|
||||||
|
db, err := gorm.Open(mysql.Open(cfg.DBConnString), &gorm.Config{})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to connect to database: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-migrate the users table
|
||||||
|
err = db.AutoMigrate(&models.User{})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to auto-migrate: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize Redis client
|
||||||
|
redisClient := config.InitRedis(cfg.RedisAddr)
|
||||||
|
|
||||||
|
// Create Fiber app
|
||||||
|
app := fiber.New()
|
||||||
|
|
||||||
|
// Set up middleware
|
||||||
|
app.Use(logger.New(logger.Config{
|
||||||
|
Format: "[${time}] ${status} - ${latency} ${method} ${path}\n",
|
||||||
|
Output: logFile,
|
||||||
|
}))
|
||||||
|
|
||||||
|
// Set up routes
|
||||||
|
app.Post("/login", handlers.Login(db, redisClient))
|
||||||
|
app.Get("/user", middleware.AuthMiddleware(redisClient), handlers.GetCurrentUser(db))
|
||||||
|
app.Put("/user", middleware.AuthMiddleware(redisClient), handlers.UpdateCurrentUser(db))
|
||||||
|
app.Get("/users/:id", middleware.AuthMiddleware(redisClient), handlers.GetUserByID(db))
|
||||||
|
|
||||||
|
// Start server
|
||||||
|
log.Fatal(app.Listen(":8080"))
|
||||||
|
}
|
||||||
23
.history/middleware/auth_20240925160148.go
Normal file
23
.history/middleware/auth_20240925160148.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/gofiber/storage/redis/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AuthMiddleware(redisClient *redis.Storage) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
token := c.Get("Authorization")
|
||||||
|
if token == "" {
|
||||||
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Missing authorization token"})
|
||||||
|
}
|
||||||
|
|
||||||
|
userID, err := redisClient.Get(token)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid or expired token"})
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Locals("user_id", userID)
|
||||||
|
return c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
23
.history/middleware/auth_20240925160239.go
Normal file
23
.history/middleware/auth_20240925160239.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/gofiber/storage/redis/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AuthMiddleware(redisClient *redis.Storage) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
token := c.Get("Authorization")
|
||||||
|
if token == "" {
|
||||||
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Missing authorization token"})
|
||||||
|
}
|
||||||
|
|
||||||
|
userID, err := redisClient.Get(token)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid or expired token"})
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Locals("user_id", userID)
|
||||||
|
return c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
6
.history/models/user_20240925101022.go
Normal file
6
.history/models/user_20240925101022.go
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Username string `json:"username" validate:"required,alphanum,min=3,max=20"`
|
||||||
|
Password string `json:"password" validate:"required,min=8,max=20"`
|
||||||
|
}
|
||||||
31
.history/models/user_20240925160020.go
Normal file
31
.history/models/user_20240925160020.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
ID uint `gorm:"primarykey" json:"id"`
|
||||||
|
Username string `gorm:"unique" json:"username"`
|
||||||
|
Password string `json:"-"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Phone string `json:"phone"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) BeforeCreate(tx *gorm.DB) error {
|
||||||
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
u.Password = string(hashedPassword)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) ComparePassword(password string) error {
|
||||||
|
return bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password))
|
||||||
|
}
|
||||||
31
.history/models/user_20240925160023.go
Normal file
31
.history/models/user_20240925160023.go
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
ID uint `gorm:"primarykey" json:"id"`
|
||||||
|
Username string `gorm:"unique" json:"username"`
|
||||||
|
Password string `json:"-"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Phone string `json:"phone"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) BeforeCreate(tx *gorm.DB) error {
|
||||||
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
u.Password = string(hashedPassword)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) ComparePassword(password string) error {
|
||||||
|
return bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password))
|
||||||
|
}
|
||||||
82
.history/routes/auth_20240925152339.go
Normal file
82
.history/routes/auth_20240925152339.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
package routes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"testfb/utils"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 注册路由
|
||||||
|
func SetupRoutes(app *fiber.App) {
|
||||||
|
app.Post("/login", login)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理登录
|
||||||
|
func login(c *fiber.Ctx) error {
|
||||||
|
//请求参数是JSON格式,解析JSON数据
|
||||||
|
var data map[string]string
|
||||||
|
if err := c.BodyParser(&data); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||||
|
"message": "Invalid request",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//把JSON数据中的用户名和密码取出来
|
||||||
|
if data["username"] == "" || data["password"] == "" {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||||
|
"message": "Invalid request",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
username := data["username"]
|
||||||
|
password := data["password"]
|
||||||
|
log.Printf("Login request for user: %s", username)
|
||||||
|
log.Printf("Password: %s", password)
|
||||||
|
//验证用户名和密码
|
||||||
|
if utils.ValiddateUser(username, password) {
|
||||||
|
token, err := utils.GenerateJWT(username)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
|
"message": "Cannot get token, Internal server error",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
log.Println("Token generated for user:", username)
|
||||||
|
return c.Status(fiber.StatusOK).JSON(fiber.Map{
|
||||||
|
"token": token,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
log.Printf("Invalid username or password for user: %s", username)
|
||||||
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
||||||
|
"message": "Invalid username or password",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到用户信息。GET /userInfo
|
||||||
|
// 验证token。GET /validateToken
|
||||||
|
func userInfo(c *fiber.Ctx) error {
|
||||||
|
// 从请求头中获取token
|
||||||
|
token := c.Get("Authorization")
|
||||||
|
if token == "" {
|
||||||
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
||||||
|
"message": "Unauthorized",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 验证token
|
||||||
|
username, err := utils.ValidateJWT(token)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
||||||
|
"message": "Unauthorized",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 得到用户信息
|
||||||
|
user, err := utils.GetUser(username)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
|
"message": "Internal server error",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return c.Status(fiber.StatusOK).JSON(user)
|
||||||
|
}
|
||||||
82
.history/routes/auth_20240925153641.go
Normal file
82
.history/routes/auth_20240925153641.go
Normal file
@ -0,0 +1,82 @@
|
|||||||
|
package routes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
"testfb/utils"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
)
|
||||||
|
|
||||||
|
// 注册路由
|
||||||
|
func SetupRoutes(app *fiber.App) {
|
||||||
|
app.Post("/login", login)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 处理登录
|
||||||
|
func login(c *fiber.Ctx) error {
|
||||||
|
//请求参数是JSON格式,解析JSON数据
|
||||||
|
var data map[string]string
|
||||||
|
if err := c.BodyParser(&data); err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||||
|
"message": "Invalid request",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
//把JSON数据中的用户名和密码取出来
|
||||||
|
if data["username"] == "" || data["password"] == "" {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{
|
||||||
|
"message": "Invalid request",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
username := data["username"]
|
||||||
|
password := data["password"]
|
||||||
|
log.Printf("Login request for user: %s", username)
|
||||||
|
log.Printf("Password: %s", password)
|
||||||
|
//验证用户名和密码
|
||||||
|
if utils.ValiddateUser(username, password) {
|
||||||
|
token, err := utils.GenerateJWT(username)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
|
"message": "Cannot get token, Internal server error",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
log.Println("Token generated for user:", username)
|
||||||
|
return c.Status(fiber.StatusOK).JSON(fiber.Map{
|
||||||
|
"token": token,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
log.Printf("Invalid username or password for user: %s", username)
|
||||||
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
||||||
|
"message": "Invalid username or password",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// 得到用户信息。GET /userInfo
|
||||||
|
// 验证token。GET /validateToken
|
||||||
|
func userInfo(c *fiber.Ctx) error {
|
||||||
|
// 从请求头中获取token
|
||||||
|
token := c.Get("Authorization")
|
||||||
|
if token == "" {
|
||||||
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
||||||
|
"message": "Unauthorized",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 验证token
|
||||||
|
username, err := utils.ValidateToken(token)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{
|
||||||
|
"message": "Unauthorized",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
// 得到用户信息
|
||||||
|
user, err := utils.GetUser(username)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{
|
||||||
|
"message": "Internal server error",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
return c.Status(fiber.StatusOK).JSON(user)
|
||||||
|
}
|
||||||
0
.history/routes/storage/mysql_20240925153315.go
Normal file
0
.history/routes/storage/mysql_20240925153315.go
Normal file
0
.history/routes/storage/mysql_20240925153633.go
Normal file
0
.history/routes/storage/mysql_20240925153633.go
Normal file
1
.history/routes/storage/mysql_20240925153638.go
Normal file
1
.history/routes/storage/mysql_20240925153638.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package storage
|
||||||
0
.history/routes/storage/redis_20240925153309.go
Normal file
0
.history/routes/storage/redis_20240925153309.go
Normal file
1
.history/routes/storage/redis_20240925153620.go
Normal file
1
.history/routes/storage/redis_20240925153620.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package storage
|
||||||
1
.history/routes/storage/redis_20240925153624.go
Normal file
1
.history/routes/storage/redis_20240925153624.go
Normal file
@ -0,0 +1 @@
|
|||||||
|
package storage
|
||||||
@ -1,8 +1,29 @@
|
|||||||
package config
|
package config
|
||||||
|
|
||||||
const (
|
import (
|
||||||
//日志文件路径
|
"github.com/gofiber/storage/redis/v3"
|
||||||
LogFilePath = "testfb.log"
|
|
||||||
//地址+端口
|
|
||||||
Port = ":3030"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type Config struct {
|
||||||
|
DBConnString string
|
||||||
|
RedisAddr string
|
||||||
|
JWTSecret string
|
||||||
|
}
|
||||||
|
|
||||||
|
func New() *Config {
|
||||||
|
return &Config{
|
||||||
|
DBConnString: "root:password@tcp(localhost:3306)/testfb?charset=utf8mb4&parseTime=True&loc=Local",
|
||||||
|
RedisAddr: "localhost:6379",
|
||||||
|
JWTSecret: "your-secret-key",
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func InitRedis(addr string) *redis.Storage {
|
||||||
|
return redis.New(redis.Config{
|
||||||
|
Host: addr,
|
||||||
|
Port: 6379,
|
||||||
|
Username: "",
|
||||||
|
Password: "",
|
||||||
|
Database: 0,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
13
go.mod
13
go.mod
@ -4,16 +4,27 @@ go 1.22.6
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/andybalholm/brotli v1.0.5 // indirect
|
github.com/andybalholm/brotli v1.0.5 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0 // indirect
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0 // indirect
|
||||||
github.com/gofiber/fiber/v2 v2.52.5 // indirect
|
github.com/gofiber/fiber/v2 v2.52.5 // indirect
|
||||||
|
github.com/gofiber/storage/redis/v3 v3.1.2 // indirect
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
|
github.com/golang-jwt/jwt/v4 v4.5.0 // indirect
|
||||||
github.com/google/uuid v1.5.0 // indirect
|
github.com/google/uuid v1.5.0 // indirect
|
||||||
|
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||||
|
github.com/jinzhu/now v1.1.5 // indirect
|
||||||
github.com/klauspost/compress v1.17.0 // indirect
|
github.com/klauspost/compress v1.17.0 // indirect
|
||||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||||
github.com/mattn/go-runewidth v0.0.15 // indirect
|
github.com/mattn/go-runewidth v0.0.15 // indirect
|
||||||
|
github.com/redis/go-redis/v9 v9.5.3 // indirect
|
||||||
github.com/rivo/uniseg v0.2.0 // indirect
|
github.com/rivo/uniseg v0.2.0 // indirect
|
||||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||||
github.com/valyala/fasthttp v1.51.0 // indirect
|
github.com/valyala/fasthttp v1.51.0 // indirect
|
||||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||||
golang.org/x/sys v0.15.0 // indirect
|
golang.org/x/crypto v0.27.0 // indirect
|
||||||
|
golang.org/x/sys v0.25.0 // indirect
|
||||||
|
golang.org/x/text v0.18.0 // indirect
|
||||||
|
gorm.io/driver/mysql v1.5.7 // indirect
|
||||||
|
gorm.io/gorm v1.25.12 // indirect
|
||||||
)
|
)
|
||||||
|
|||||||
27
go.sum
27
go.sum
@ -1,11 +1,23 @@
|
|||||||
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
github.com/andybalholm/brotli v1.0.5 h1:8uQZIdzKmjc/iuPu7O2ioW48L81FgatrcpfFmiq/cCs=
|
||||||
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
github.com/andybalholm/brotli v1.0.5/go.mod h1:fO7iG3H7G2nSZ7m0zPUDn85XEX2GTukHGRSepvi9Eig=
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44=
|
||||||
|
github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78=
|
||||||
|
github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc=
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0 h1:ueSltNNllEqE3qcWBTD0iQd3IpL/6U+mJxLkazJ7YPc=
|
||||||
|
github.com/go-sql-driver/mysql v1.7.0/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI=
|
||||||
github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo=
|
github.com/gofiber/fiber/v2 v2.52.5 h1:tWoP1MJQjGEe4GB5TUGOi7P2E0ZMMRx5ZTG4rT+yGMo=
|
||||||
github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
|
github.com/gofiber/fiber/v2 v2.52.5/go.mod h1:KEOE+cXMhXG0zHc9d8+E38hoX+ZN7bhOtgeF2oT6jrQ=
|
||||||
|
github.com/gofiber/storage/redis/v3 v3.1.2 h1:qYHSRbkRQCD9HovLOOoswe+DoGF28/hwD4d8kmxDNcs=
|
||||||
|
github.com/gofiber/storage/redis/v3 v3.1.2/go.mod h1:bwSKrd5Ux2blqXVT8tWOYTmZbFDMZR8dztn7rarDZiU=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg=
|
||||||
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU=
|
||||||
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
||||||
|
github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E=
|
||||||
|
github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc=
|
||||||
|
github.com/jinzhu/now v1.1.5 h1:/o9tlHleP7gOFmsnYNz3RGnqzefHA47wQpKrrdTIwXQ=
|
||||||
|
github.com/jinzhu/now v1.1.5/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
|
||||||
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
github.com/klauspost/compress v1.17.0 h1:Rnbp4K9EjcDuVuHtd0dgA4qNuv9yKDYKK1ulpJwgrqM=
|
||||||
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
github.com/klauspost/compress v1.17.0/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE=
|
||||||
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA=
|
||||||
@ -15,6 +27,8 @@ github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWE
|
|||||||
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y=
|
||||||
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
github.com/mattn/go-runewidth v0.0.15 h1:UNAjwbU9l54TA3KzvqLGxwWjHmMgBUVhBiTjelZgg3U=
|
||||||
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
github.com/mattn/go-runewidth v0.0.15/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w=
|
||||||
|
github.com/redis/go-redis/v9 v9.5.3 h1:fOAp1/uJG+ZtcITgZOfYFmTKPE7n4Vclj1wZFgRciUU=
|
||||||
|
github.com/redis/go-redis/v9 v9.5.3/go.mod h1:hdY0cQFCN4fnSYT6TkisLufl/4W5UIXyv0b/CLO2V2M=
|
||||||
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
github.com/rivo/uniseg v0.2.0 h1:S1pD9weZBuJdFmowNwbpi7BJ8TNftyUImj/0WQi72jY=
|
||||||
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc=
|
||||||
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
|
||||||
@ -23,7 +37,20 @@ github.com/valyala/fasthttp v1.51.0 h1:8b30A5JlZ6C7AS81RsWjYMQmrZG6feChmgAolCl1S
|
|||||||
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
|
github.com/valyala/fasthttp v1.51.0/go.mod h1:oI2XroL+lI7vdXyYoQk03bXBThfFl2cVdIA3Xl7cH8g=
|
||||||
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
|
||||||
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
|
||||||
|
golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A=
|
||||||
|
golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70=
|
||||||
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc=
|
||||||
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34=
|
||||||
|
golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
|
||||||
|
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
|
||||||
|
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
|
||||||
|
golang.org/x/text v0.18.0 h1:XvMDiNzPAl0jr17s6W9lcaIhGUfUORdGCNsuLmPG224=
|
||||||
|
golang.org/x/text v0.18.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY=
|
||||||
|
gorm.io/driver/mysql v1.5.7 h1:MndhOPYOfEp2rHKgkZIhJ16eVUIRf2HmzgoPmh7FCWo=
|
||||||
|
gorm.io/driver/mysql v1.5.7/go.mod h1:sEtPWMiqiN1N1cMXoXmBbd8C6/l+TESwriotuRRpkDM=
|
||||||
|
gorm.io/gorm v1.25.7/go.mod h1:hbnx/Oo0ChWMn1BIhpy1oYozzpM15i4YPuHDmfYtwg8=
|
||||||
|
gorm.io/gorm v1.25.12 h1:I0u8i2hWQItBq1WfE0o2+WuL9+8L21K9e2HHSTE/0f8=
|
||||||
|
gorm.io/gorm v1.25.12/go.mod h1:xh7N7RHfYlNc5EmcI/El95gXusucDrQnHXe0+CgWcLQ=
|
||||||
|
|||||||
102
handlers/handlers.go
Normal file
102
handlers/handlers.go
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/gofiber/storage/redis/v3"
|
||||||
|
"github.com/golang-jwt/jwt/v4"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"testfb/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Login(db *gorm.DB, redisClient *redis.Storage) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
var input struct {
|
||||||
|
Username string `json:"username"`
|
||||||
|
Password string `json:"password"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := c.BodyParser(&input); err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid input"})
|
||||||
|
}
|
||||||
|
|
||||||
|
var user models.User
|
||||||
|
if err := db.Where("username = ?", input.Username).First(&user).Error; err != nil {
|
||||||
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid credentials"})
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := user.ComparePassword(input.Password); err != nil {
|
||||||
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid credentials"})
|
||||||
|
}
|
||||||
|
|
||||||
|
token := jwt.New(jwt.SigningMethodHS256)
|
||||||
|
claims := token.Claims.(jwt.MapClaims)
|
||||||
|
claims["user_id"] = user.ID
|
||||||
|
claims["exp"] = time.Now().Add(time.Hour * 24).Unix()
|
||||||
|
|
||||||
|
t, err := token.SignedString([]byte("your-secret-key"))
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Could not login"})
|
||||||
|
}
|
||||||
|
|
||||||
|
err = redisClient.Set(t, user.ID, 24*time.Hour)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Could not store token"})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(fiber.Map{"token": t})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetCurrentUser(db *gorm.DB) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
userID := c.Locals("user_id").(uint)
|
||||||
|
|
||||||
|
var user models.User
|
||||||
|
if err := db.First(&user, userID).Error; err != nil {
|
||||||
|
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "User not found"})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func UpdateCurrentUser(db *gorm.DB) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
userID := c.Locals("user_id").(uint)
|
||||||
|
|
||||||
|
var input models.User
|
||||||
|
if err := c.BodyParser(&input); err != nil {
|
||||||
|
return c.Status(fiber.StatusBadRequest).JSON(fiber.Map{"error": "Invalid input"})
|
||||||
|
}
|
||||||
|
|
||||||
|
var user models.User
|
||||||
|
if err := db.First(&user, userID).Error; err != nil {
|
||||||
|
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "User not found"})
|
||||||
|
}
|
||||||
|
|
||||||
|
user.Email = input.Email
|
||||||
|
user.Phone = input.Phone
|
||||||
|
|
||||||
|
if err := db.Save(&user).Error; err != nil {
|
||||||
|
return c.Status(fiber.StatusInternalServerError).JSON(fiber.Map{"error": "Could not update user"})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(user)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func GetUserByID(db *gorm.DB) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
id := c.Params("id")
|
||||||
|
|
||||||
|
var user models.User
|
||||||
|
if err := db.First(&user, id).Error; err != nil {
|
||||||
|
return c.Status(fiber.StatusNotFound).JSON(fiber.Map{"error": "User not found"})
|
||||||
|
}
|
||||||
|
|
||||||
|
return c.JSON(user)
|
||||||
|
}
|
||||||
|
}
|
||||||
60
main.go
60
main.go
@ -4,32 +4,58 @@ import (
|
|||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
|
|
||||||
"testfb/config"
|
|
||||||
"testfb/routes"
|
|
||||||
|
|
||||||
"github.com/gofiber/fiber/v2"
|
"github.com/gofiber/fiber/v2"
|
||||||
"github.com/gofiber/fiber/v2/middleware/logger"
|
"github.com/gofiber/fiber/v2/middleware/logger"
|
||||||
|
"gorm.io/driver/mysql"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
|
||||||
|
"testfb/config"
|
||||||
|
"testfb/handlers"
|
||||||
|
"testfb/middleware"
|
||||||
|
"testfb/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
//创建日志文件
|
// Initialize configuration
|
||||||
f, err := os.OpenFile(config.LogFilePath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
|
cfg := config.New()
|
||||||
if err != nil {
|
|
||||||
log.Fatalln("日志文件创建失败:", err)
|
|
||||||
}
|
|
||||||
defer f.Close()
|
|
||||||
|
|
||||||
|
// Set up logging
|
||||||
|
logFile, err := os.OpenFile("app.log", os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Error opening log file: %v", err)
|
||||||
|
}
|
||||||
|
defer logFile.Close()
|
||||||
|
|
||||||
|
// Initialize database
|
||||||
|
db, err := gorm.Open(mysql.Open(cfg.DBConnString), &gorm.Config{})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to connect to database: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Auto-migrate the users table
|
||||||
|
err = db.AutoMigrate(&models.User{})
|
||||||
|
if err != nil {
|
||||||
|
log.Fatalf("Failed to auto-migrate: %v", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize Redis client
|
||||||
|
redisClient := config.InitRedis(cfg.RedisAddr)
|
||||||
|
|
||||||
|
// Create Fiber app
|
||||||
app := fiber.New()
|
app := fiber.New()
|
||||||
|
|
||||||
|
// Set up middleware
|
||||||
app.Use(logger.New(logger.Config{
|
app.Use(logger.New(logger.Config{
|
||||||
Output: f,
|
Format: "[${time}] ${status} - ${latency} ${method} ${path}\n",
|
||||||
|
Output: logFile,
|
||||||
}))
|
}))
|
||||||
|
|
||||||
//注册路由
|
// Set up routes
|
||||||
routes.SetupRoutes(app)
|
app.Post("/login", handlers.Login(db, redisClient))
|
||||||
// 启动服务
|
app.Get("/user", middleware.AuthMiddleware(redisClient), handlers.GetCurrentUser(db))
|
||||||
log.Println("服务启动成功,监听端口:", config.Port)
|
app.Put("/user", middleware.AuthMiddleware(redisClient), handlers.UpdateCurrentUser(db))
|
||||||
if err := app.Listen(config.Port); err != nil {
|
app.Get("/users/:id", middleware.AuthMiddleware(redisClient), handlers.GetUserByID(db))
|
||||||
log.Fatalln("服务启动失败:", err)
|
|
||||||
}
|
// Start server
|
||||||
|
log.Fatal(app.Listen(":7777"))
|
||||||
}
|
}
|
||||||
|
|||||||
23
middleware/auth.go
Normal file
23
middleware/auth.go
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
package middleware
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/gofiber/fiber/v2"
|
||||||
|
"github.com/gofiber/storage/redis/v3"
|
||||||
|
)
|
||||||
|
|
||||||
|
func AuthMiddleware(redisClient *redis.Storage) fiber.Handler {
|
||||||
|
return func(c *fiber.Ctx) error {
|
||||||
|
token := c.Get("Authorization")
|
||||||
|
if token == "" {
|
||||||
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Missing authorization token"})
|
||||||
|
}
|
||||||
|
|
||||||
|
userID, err := redisClient.Get(token)
|
||||||
|
if err != nil {
|
||||||
|
return c.Status(fiber.StatusUnauthorized).JSON(fiber.Map{"error": "Invalid or expired token"})
|
||||||
|
}
|
||||||
|
|
||||||
|
c.Locals("user_id", userID)
|
||||||
|
return c.Next()
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,31 @@
|
|||||||
package models
|
package models
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
"gorm.io/gorm"
|
||||||
|
)
|
||||||
|
|
||||||
type User struct {
|
type User struct {
|
||||||
Username string `json:"username" validate:"required,alphanum,min=3,max=20"`
|
ID uint `gorm:"primarykey" json:"id"`
|
||||||
Password string `json:"password" validate:"required,min=8,max=20"`
|
Username string `gorm:"unique" json:"username"`
|
||||||
|
Password string `json:"-"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Phone string `json:"phone"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
UpdatedAt time.Time `json:"updated_at"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) BeforeCreate(tx *gorm.DB) error {
|
||||||
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
u.Password = string(hashedPassword)
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) ComparePassword(password string) error {
|
||||||
|
return bcrypt.CompareHashAndPassword([]byte(u.Password), []byte(password))
|
||||||
}
|
}
|
||||||
|
|||||||
18
testfb.log
18
testfb.log
@ -1,18 +0,0 @@
|
|||||||
09:42:05 | 404 | 107.091µs | 127.0.0.1 | POST | / | Cannot POST /
|
|
||||||
09:43:05 | 404 | 9.871µs | 127.0.0.1 | POST | / | Cannot POST /
|
|
||||||
09:43:20 | 404 | 9.475µs | 127.0.0.1 | POST | / | Cannot POST /
|
|
||||||
09:43:33 | 404 | 9.491µs | 127.0.0.1 | POST | / | Cannot POST /
|
|
||||||
09:43:49 | 400 | 207.706µs | 127.0.0.1 | POST | /login | -
|
|
||||||
09:43:55 | 401 | 80.159µs | 127.0.0.1 | POST | /login | -
|
|
||||||
09:45:52 | 401 | 65.554µs | 127.0.0.1 | POST | /login | -
|
|
||||||
09:47:38 | 401 | 155.702µs | 127.0.0.1 | POST | /login | -
|
|
||||||
09:47:48 | 400 | 90.98µs | 127.0.0.1 | POST | /login | -
|
|
||||||
09:48:00 | 400 | 64.331µs | 127.0.0.1 | POST | /login | -
|
|
||||||
09:48:06 | 401 | 81.624µs | 127.0.0.1 | POST | /login | -
|
|
||||||
09:52:52 | 401 | 188.948µs | 127.0.0.1 | POST | /login | -
|
|
||||||
09:54:47 | 200 | 242.308µs | 127.0.0.1 | POST | /login | -
|
|
||||||
09:55:40 | 400 | 72.042µs | 127.0.0.1 | POST | /login | -
|
|
||||||
09:55:47 | 200 | 126.783µs | 127.0.0.1 | POST | /login | -
|
|
||||||
09:55:52 | 200 | 82.231µs | 127.0.0.1 | POST | /login | -
|
|
||||||
09:55:56 | 401 | 83.999µs | 127.0.0.1 | POST | /login | -
|
|
||||||
09:56:01 | 200 | 71.148µs | 127.0.0.1 | POST | /login | -
|
|
||||||
26
utils/jwt.go
26
utils/jwt.go
@ -1,26 +0,0 @@
|
|||||||
package utils
|
|
||||||
|
|
||||||
import (
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"github.com/golang-jwt/jwt/v4"
|
|
||||||
)
|
|
||||||
|
|
||||||
// 密钥 (签发JWT)
|
|
||||||
var jwtSecret = []byte("mysecretkey")
|
|
||||||
|
|
||||||
// 模拟用户验证
|
|
||||||
func ValiddateUser(username, password string) bool {
|
|
||||||
return username == "admin" && password == "123456"
|
|
||||||
}
|
|
||||||
|
|
||||||
// 生成JWT
|
|
||||||
func GenerateJWT(username string) (string, error) {
|
|
||||||
// 设置过期时间
|
|
||||||
claims := jwt.MapClaims{
|
|
||||||
"username": username,
|
|
||||||
"exp": time.Now().Add(time.Hour * 72).Unix(),
|
|
||||||
}
|
|
||||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
|
||||||
return token.SignedString(jwtSecret)
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user