From 9ba861fe9084200a32d324cf18fe6c2be80fa870 Mon Sep 17 00:00:00 2001 From: Mathieu Coulet Date: Fri, 29 Nov 2024 16:56:25 +0100 Subject: [PATCH] feat(MariaDB ORM): Simple MariaDB with authentification --- rabbit-mq/docker-compose.yml | 19 --------------- rabbit-mq/rabbitmq.conf | 1 - server/config.json | 7 ++++++ server/go.mod | 5 ++++ server/go.sum | 12 ++++++++++ server/internal/config/config.go | 9 +++++++ server/internal/controllers/auth.go | 37 ++++++++++++++++------------- server/internal/middleware/auth.go | 12 +++++++++- server/internal/models/all.go | 16 +++++++++++++ server/internal/models/users.go | 12 ++++++++++ server/internal/pkg/db.go | 25 +++++++++++++++++++ server/internal/routers/routers.go | 2 +- server/internal/utils/token.go | 21 ++++++++++++++++ server/main.go | 7 ++++++ 14 files changed, 147 insertions(+), 38 deletions(-) delete mode 100644 rabbit-mq/docker-compose.yml delete mode 100644 rabbit-mq/rabbitmq.conf create mode 100644 server/internal/models/all.go create mode 100644 server/internal/models/users.go create mode 100644 server/internal/pkg/db.go create mode 100644 server/internal/utils/token.go diff --git a/rabbit-mq/docker-compose.yml b/rabbit-mq/docker-compose.yml deleted file mode 100644 index a159018..0000000 --- a/rabbit-mq/docker-compose.yml +++ /dev/null @@ -1,19 +0,0 @@ -services: - rabbitmq: - image: rabbitmq:3-management - ports: - - "8080:15672" - - "5000:5673" - networks: - - rabbitmq_network - volumes: - - ./rabbitmq.conf:/etc/rabbitmq/rabbitmq.conf:ro - healthcheck: - test: [ "CMD", "rabbitmqctl", "status" ] - interval: 5s - timeout: 15s - retries: 5 - -networks: - rabbitmq_network: - driver: bridge diff --git a/rabbit-mq/rabbitmq.conf b/rabbit-mq/rabbitmq.conf deleted file mode 100644 index 3b1a462..0000000 --- a/rabbit-mq/rabbitmq.conf +++ /dev/null @@ -1 +0,0 @@ -listeners.tcp.default = 5673 \ No newline at end of file diff --git a/server/config.json b/server/config.json index 9f5fa75..56a81f4 100644 --- a/server/config.json +++ b/server/config.json @@ -4,6 +4,13 @@ "gin_mode": "debug", "secret_key": "your-secure-secret-key", "cors": true, + "db": { + "host": "127.0.1", + "port": 3306, + "name": "area", + "user": "root", + "password": "root" + }, "swagger": true, "cors_origins": [ "http://localhost:3000", diff --git a/server/go.mod b/server/go.mod index b721366..ba3c3a8 100644 --- a/server/go.mod +++ b/server/go.mod @@ -28,10 +28,13 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/validator/v10 v10.23.0 // indirect + github.com/go-sql-driver/mysql v1.7.0 // indirect github.com/goccy/go-json v0.10.3 // indirect github.com/gookit/color v1.5.4 // indirect github.com/gookit/goutil v0.6.17 // indirect github.com/hashicorp/hcl v1.0.0 // indirect + github.com/jinzhu/inflection v1.0.0 // indirect + github.com/jinzhu/now v1.1.5 // indirect github.com/josharian/intern v1.0.0 // indirect github.com/json-iterator/go v1.1.12 // indirect github.com/klauspost/cpuid/v2 v2.2.9 // indirect @@ -71,6 +74,8 @@ require ( google.golang.org/protobuf v1.35.2 // indirect gopkg.in/ini.v1 v1.67.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect + gorm.io/driver/mysql v1.5.7 // indirect + gorm.io/gorm v1.25.12 // indirect ) go 1.23.3 diff --git a/server/go.sum b/server/go.sum index d7819d3..52de721 100644 --- a/server/go.sum +++ b/server/go.sum @@ -47,6 +47,8 @@ github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJn github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/validator/v10 v10.23.0 h1:/PwmTwZhS0dPkav3cdK9kV1FsAmrL8sThn8IHr/sO+o= github.com/go-playground/validator/v10 v10.23.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM= +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/goccy/go-json v0.10.3 h1:KZ5WoDbxAIgm2HNbYckL0se1fHD6rz5j4ywS6ebzDqA= github.com/goccy/go-json v0.10.3/go.mod h1:oq7eo15ShAhp70Anwd5lgX2pLfOS3QCiwU/PULtXL6M= github.com/goccy/go-yaml v1.11.2 h1:joq77SxuyIs9zzxEjgyLBugMQ9NEgTWxXfz2wVqwAaQ= @@ -65,6 +67,10 @@ github.com/gookit/ini/v2 v2.2.3 h1:nSbN+x9OfQPcMObTFP+XuHt8ev6ndv/fWWqxFhPMu2E= github.com/gookit/ini/v2 v2.2.3/go.mod h1:Vu6p7P7xcfmb8KYu3L0ek8bqu/Im63N81q208SCCZY4= github.com/hashicorp/hcl v1.0.0 h1:0Anlzjpi4vEasTeNFn2mLJgTSwt0+6sfsiTG8qcWGx4= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= +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/josharian/intern v1.0.0 h1:vlS4z54oSdjm0bgjRigI+G1HpF+tI+9rE5LLzOg8HmY= github.com/josharian/intern v1.0.0/go.mod h1:5DoeVV0s6jJacbCEi61lwdGj/aVlrQvzHFFd8Hwg//Y= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= @@ -216,4 +222,10 @@ gopkg.in/ini.v1 v1.67.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +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 h1:VsD6acwRjz2zFxGO50gPO6AkNs7KKnvfzUjHQhZDz/A= +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= nullprogram.com/x/optparse v1.0.0/go.mod h1:KdyPE+Igbe0jQUrVfMqDMeJQIJZEuyV7pjYmp6pbG50= diff --git a/server/internal/config/config.go b/server/internal/config/config.go index c2acb61..2a1d02b 100644 --- a/server/internal/config/config.go +++ b/server/internal/config/config.go @@ -8,6 +8,14 @@ import ( var AppConfig *Config +type DB struct { + Host string `mapstructure:"host"` + Port int `mapstructure:"port"` + Name string `mapstructure:"name"` + User string `mapstructure:"user"` + Password string `mapstructure:"password"` +} + type Config struct { AppName string `mapstructure:"app_name"` Port int `mapstructure:"port"` @@ -16,6 +24,7 @@ type Config struct { CorsOrigins []string `mapstructure:"cors_origins"` SecretKey string `mapstructure:"secret_key"` Swagger bool `mapstructure:"swagger"` + DB DB `mapstructure:"db"` } func LoadConfig() { diff --git a/server/internal/controllers/auth.go b/server/internal/controllers/auth.go index 12f293c..f88565b 100644 --- a/server/internal/controllers/auth.go +++ b/server/internal/controllers/auth.go @@ -1,11 +1,11 @@ package controllers import ( - "AREA/internal/config" - "github.com/dgrijalva/jwt-go" + "AREA/internal/models" + "AREA/internal/pkg" + "AREA/internal/utils" "github.com/gin-gonic/gin" "net/http" - "time" ) // Login godoc @@ -23,19 +23,14 @@ import ( func Login(c *gin.Context) { email := c.PostForm("email") password := c.PostForm("password") - if password != "password" { + var user models.User + db.DB.Where("email = ? AND password = ?", email, password).First(&user) + if user.ID == 0 { c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid credentials"}) return } - token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ - "email": email, - "exp": time.Now().Add(time.Hour * 1).Unix(), - }) - tokenString, err := token.SignedString([]byte(config.AppConfig.SecretKey)) - if err != nil { - c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"}) - return - } + tokenString := utils.NewToken(c, email) + db.DB.Model(&user).Update("token", tokenString) c.JSON(http.StatusOK, gin.H{"token": tokenString}) } @@ -50,7 +45,17 @@ func Login(c *gin.Context) { // @Success 201 {object} map[string]string // @Router /register [post] func Register(c *gin.Context) { - c.PostForm("email") - c.PostForm("password") - c.JSON(http.StatusCreated, gin.H{"message": "User created"}) + tokenString := utils.NewToken(c, c.PostForm("email")) + var user models.User + db.DB.Where("email = ?", c.PostForm("email")).First(&user) + if user.ID != 0 { + c.JSON(http.StatusConflict, gin.H{"error": "User already exists"}) + return + } + db.DB.Create(&models.User{ + Email: c.PostForm("email"), + Password: c.PostForm("password"), + Token: tokenString, + }) + c.JSON(http.StatusOK, gin.H{"token": tokenString}) } diff --git a/server/internal/middleware/auth.go b/server/internal/middleware/auth.go index 05e9a25..9c5a2c9 100644 --- a/server/internal/middleware/auth.go +++ b/server/internal/middleware/auth.go @@ -1,6 +1,8 @@ package middleware import ( + "AREA/internal/models" + db "AREA/internal/pkg" "github.com/gin-gonic/gin" "net/http" ) @@ -16,6 +18,14 @@ func AuthMiddleware() gin.HandlerFunc { } func isAuthenticated(c *gin.Context) bool { - // TODO: Implement authentication + token := c.GetHeader("Authorization") + if token == "" { + return false + } + user := models.User{} + db.DB.Where("token = ?", token).First(&user) + if user.ID == 0 { + return false + } return true } diff --git a/server/internal/models/all.go b/server/internal/models/all.go new file mode 100644 index 0000000..b96c8a9 --- /dev/null +++ b/server/internal/models/all.go @@ -0,0 +1,16 @@ +package models + +import "gorm.io/gorm" + +type Subscribed struct { + gorm.Model + UserID uint `gorm:"not null" json:"user_id"` + Provider string `gorm:"not null" json:"provider"` + ProviderID string `gorm:"not null" json:"provider_id"` + AccessToken string `gorm:"not null" json:"access_token"` +} + +type Users struct { + User User `gorm:"embedded"` + Subscribed []Subscribed `gorm:"foreignKey:UserID"` +} diff --git a/server/internal/models/users.go b/server/internal/models/users.go new file mode 100644 index 0000000..4a217c3 --- /dev/null +++ b/server/internal/models/users.go @@ -0,0 +1,12 @@ +package models + +import ( + "gorm.io/gorm" +) + +type User struct { + gorm.Model + Email string `gorm:"unique;not null" json:"email" binding:"required"` + Password string `gorm:"not null" json:"password" binding:"required"` + Token string `gorm:"not null" json:"token"` +} diff --git a/server/internal/pkg/db.go b/server/internal/pkg/db.go new file mode 100644 index 0000000..3deebdf --- /dev/null +++ b/server/internal/pkg/db.go @@ -0,0 +1,25 @@ +package db + +import ( + "AREA/internal/config" + "fmt" + "gorm.io/driver/mysql" + "gorm.io/gorm" + "log" + "strconv" +) + +var DB *gorm.DB + +func InitDB() { + + user := config.AppConfig.DB.User + password := config.AppConfig.DB.Password + dsn := user + ":" + password + "@tcp(" + config.AppConfig.DB.Host + ":" + strconv.Itoa(config.AppConfig.DB.Port) + ")/" + config.AppConfig.DB.Name + "?parseTime=true" + err := error(nil) + DB, err = gorm.Open(mysql.Open(dsn), &gorm.Config{}) + if err != nil { + log.Fatalf("failed to initialize database, got error %v", err) + } + fmt.Println("Database connection established") +} diff --git a/server/internal/routers/routers.go b/server/internal/routers/routers.go index 28815c5..beb61eb 100644 --- a/server/internal/routers/routers.go +++ b/server/internal/routers/routers.go @@ -23,13 +23,13 @@ func SetupRouter() *gin.Engine { { public.POST("/register", controllers.Register) public.POST("/login", controllers.Login) - public.GET("/about.json", controllers.About) public.GET("/ping", controllers.Ping) public.POST("/publish/message", controllers.Message) } protected := router.Group("/") protected.Use(middleware.AuthMiddleware()) { + protected.GET("/about.json", controllers.About) //protected.GET("/users", controllers.GetUsers) } return router diff --git a/server/internal/utils/token.go b/server/internal/utils/token.go new file mode 100644 index 0000000..19f6716 --- /dev/null +++ b/server/internal/utils/token.go @@ -0,0 +1,21 @@ +package utils + +import ( + "AREA/internal/config" + "github.com/dgrijalva/jwt-go" + "github.com/gin-gonic/gin" + "net/http" + "time" +) + +func NewToken(c *gin.Context, email string) string { + token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ + "email": email, + "exp": time.Now().Add(time.Hour * 1).Unix(), + }) + tokenString, err := token.SignedString([]byte(config.AppConfig.SecretKey)) + if err != nil { + c.JSON(http.StatusInternalServerError, gin.H{"error": "Failed to generate token"}) + } + return tokenString +} diff --git a/server/main.go b/server/main.go index fecb455..346d498 100644 --- a/server/main.go +++ b/server/main.go @@ -2,6 +2,8 @@ package main import ( "AREA/internal/config" + "AREA/internal/models" + "AREA/internal/pkg" "AREA/internal/routers" "fmt" "github.com/gin-gonic/gin" @@ -25,6 +27,11 @@ import ( // @BasePath / func main() { config.LoadConfig() + db.InitDB() + err := db.DB.AutoMigrate(&models.Users{}) + if err != nil { + return + } gin.SetMode(config.AppConfig.GinMode) router := routers.SetupRouter() port := strconv.Itoa(config.AppConfig.Port)