After Finish User Register and Login Service via MVC arch
This commit is contained in:
1
.idea/.name
generated
Normal file
1
.idea/.name
generated
Normal file
@@ -0,0 +1 @@
|
||||
GinTutorial
|
||||
2
.idea/modules.xml
generated
2
.idea/modules.xml
generated
@@ -2,7 +2,7 @@
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/GinWithGormTutorial.iml" filepath="$PROJECT_DIR$/.idea/GinWithGormTutorial.iml" />
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/GinTutorial.iml" filepath="$PROJECT_DIR$/.idea/GinTutorial.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
||||
@@ -19,6 +19,9 @@ type Config struct {
|
||||
Name string
|
||||
Charset string
|
||||
}
|
||||
Bcrypt struct {
|
||||
Cost int
|
||||
}
|
||||
}
|
||||
|
||||
var AppConfig *Config
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"GinWithGormTutorial/global"
|
||||
"GinTutorial/global"
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
func buildDSN(user, password, host, port, db, charset string) string {
|
||||
template := "%s:%s@tcp(%s:%s)/%s?charset=%s"
|
||||
template := "%s:%s@tcp(%s:%s)/%s?charset=%s&parseTime=true"
|
||||
return fmt.Sprintf(template, user, password, host, port, db, charset)
|
||||
}
|
||||
|
||||
|
||||
102
controllers/auth_controller.go
Normal file
102
controllers/auth_controller.go
Normal file
@@ -0,0 +1,102 @@
|
||||
package controllers
|
||||
|
||||
import (
|
||||
"GinTutorial/global"
|
||||
"GinTutorial/models"
|
||||
"GinTutorial/utils"
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func Register(ctx *gin.Context) {
|
||||
var user models.User
|
||||
|
||||
if err := ctx.ShouldBindJSON(&user); err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
hashPassword, err := utils.HashPassword(user.Password)
|
||||
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
}
|
||||
|
||||
user.Password = hashPassword
|
||||
|
||||
if err := global.Db.AutoMigrate(&user); err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if err := global.Db.Create(&user).Error; err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
token, err := utils.GenerateJWT(strconv.Itoa(int(user.ID)))
|
||||
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, gin.H{
|
||||
"token": token,
|
||||
})
|
||||
}
|
||||
|
||||
func Login(ctx *gin.Context) {
|
||||
var InputUser struct {
|
||||
Username string `json:"username" binding:"required"`
|
||||
Password string `json:"password" binding:"required"`
|
||||
}
|
||||
|
||||
if err := ctx.ShouldBindJSON(&InputUser); err != nil {
|
||||
ctx.JSON(http.StatusBadRequest, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
var user models.User
|
||||
|
||||
if err := global.Db.Where("username = ?", InputUser.Username).First(&user).Error; err != nil {
|
||||
ctx.JSON(http.StatusUnauthorized, gin.H{
|
||||
"error": "Invalid username or password",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
if !utils.CheckPassword(InputUser.Password, user.Password) {
|
||||
ctx.JSON(http.StatusUnauthorized, gin.H{
|
||||
"error": "Invalid username or password",
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
token, err := utils.GenerateJWT(strconv.Itoa(int(user.ID)))
|
||||
|
||||
if err != nil {
|
||||
ctx.JSON(http.StatusInternalServerError, gin.H{
|
||||
"error": err.Error(),
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
ctx.JSON(http.StatusOK, gin.H{
|
||||
"token": token,
|
||||
})
|
||||
}
|
||||
7
go.mod
7
go.mod
@@ -1,10 +1,12 @@
|
||||
module GinWithGormTutorial
|
||||
module GinTutorial
|
||||
|
||||
go 1.24
|
||||
|
||||
require (
|
||||
github.com/gin-gonic/gin v1.10.1
|
||||
github.com/golang-jwt/jwt/v5 v5.2.3
|
||||
github.com/spf13/viper v1.20.1
|
||||
golang.org/x/crypto v0.40.0
|
||||
gorm.io/driver/mysql v1.6.0
|
||||
gorm.io/gorm v1.30.0
|
||||
)
|
||||
@@ -45,8 +47,7 @@ require (
|
||||
go.uber.org/atomic v1.9.0 // indirect
|
||||
go.uber.org/multierr v1.9.0 // indirect
|
||||
golang.org/x/arch v0.8.0 // indirect
|
||||
golang.org/x/crypto v0.32.0 // indirect
|
||||
golang.org/x/net v0.33.0 // indirect
|
||||
golang.org/x/net v0.41.0 // indirect
|
||||
golang.org/x/sys v0.34.0 // indirect
|
||||
golang.org/x/text v0.27.0 // indirect
|
||||
google.golang.org/protobuf v1.36.1 // indirect
|
||||
|
||||
10
go.sum
10
go.sum
@@ -35,6 +35,8 @@ github.com/go-viper/mapstructure/v2 v2.2.1 h1:ZAaOCxANMuZx5RCeg0mBdEZk7DZasvvZIx
|
||||
github.com/go-viper/mapstructure/v2 v2.2.1/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM=
|
||||
github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
|
||||
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.3 h1:kkGXqQOBSDDWRhWNXTFpqGSCMyh/PLnqUvMGJPDJDs0=
|
||||
github.com/golang-jwt/jwt/v5 v5.2.3/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
|
||||
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
|
||||
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
|
||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||
@@ -102,10 +104,10 @@ go.uber.org/multierr v1.9.0/go.mod h1:X2jQV1h+kxSjClGpnseKVIxpmcjrj7MNnI0bnlfKTV
|
||||
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
|
||||
golang.org/x/arch v0.8.0 h1:3wRIsP3pM4yUptoR96otTUOXI367OS0+c9eeRi9doIc=
|
||||
golang.org/x/arch v0.8.0/go.mod h1:FEVrYAQjsQXMVJ1nsMoVVXPZg6p2JE2mx8psSWTDQys=
|
||||
golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc=
|
||||
golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc=
|
||||
golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
|
||||
golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
|
||||
golang.org/x/crypto v0.40.0 h1:r4x+VvoG5Fm+eJcxMaY8CQM7Lb0l1lsmjGBQ6s8BfKM=
|
||||
golang.org/x/crypto v0.40.0/go.mod h1:Qr1vMER5WyS2dfPHAlsOj01wgLbsyWtFn/aY+5+ZdxY=
|
||||
golang.org/x/net v0.41.0 h1:vBTly1HeNPEn3wtREYfy4GZ/NECgw2Cnl+nK6Nz3uvw=
|
||||
golang.org/x/net v0.41.0/go.mod h1:B/K4NNqkfmg07DQYrbwvSluqCJOOXwUjeb/5lOisjbA=
|
||||
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||
golang.org/x/sys v0.34.0 h1:H5Y5sJ2L2JRdyv7ROF1he/lPdvFsd0mJHFw2ThKHxLA=
|
||||
|
||||
4
main.go
4
main.go
@@ -1,8 +1,8 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"GinWithGormTutorial/config"
|
||||
"GinWithGormTutorial/router"
|
||||
"GinTutorial/config"
|
||||
"GinTutorial/router"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
11
models/user.go
Normal file
11
models/user.go
Normal file
@@ -0,0 +1,11 @@
|
||||
package models
|
||||
|
||||
import (
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type User struct {
|
||||
gorm.Model
|
||||
Username string `grom:"unique"`
|
||||
Password string `grom:"size:255" gorm:"not null"`
|
||||
}
|
||||
@@ -1,6 +1,10 @@
|
||||
package router
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
import (
|
||||
"GinTutorial/controllers"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func SetupRouter() *gin.Engine {
|
||||
r := gin.Default()
|
||||
@@ -10,12 +14,8 @@ func SetupRouter() *gin.Engine {
|
||||
{
|
||||
auth := v1.Group("/auth")
|
||||
{
|
||||
auth.POST("/login", func(context *gin.Context) {
|
||||
context.JSON(200, gin.H{
|
||||
"msg": "Login successfully",
|
||||
})
|
||||
})
|
||||
auth.POST("/register")
|
||||
auth.POST("/login", controllers.Login)
|
||||
auth.POST("/register", controllers.Register)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
29
utils/utils.go
Normal file
29
utils/utils.go
Normal file
@@ -0,0 +1,29 @@
|
||||
package utils
|
||||
|
||||
import (
|
||||
"GinTutorial/config"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"golang.org/x/crypto/bcrypt"
|
||||
)
|
||||
|
||||
func HashPassword(password string) (string, error) {
|
||||
hash, err := bcrypt.GenerateFromPassword([]byte(password), config.AppConfig.Bcrypt.Cost)
|
||||
return string(hash), err
|
||||
}
|
||||
|
||||
func GenerateJWT(username string) (string, error) {
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS512, jwt.MapClaims{
|
||||
"username": username,
|
||||
"exp": time.Now().Add(time.Hour * 72).Unix(),
|
||||
})
|
||||
|
||||
signedToken, err := token.SignedString([]byte("secret"))
|
||||
return "Bearer " + signedToken, err
|
||||
}
|
||||
|
||||
func CheckPassword(password, hash string) bool {
|
||||
err := bcrypt.CompareHashAndPassword([]byte(hash), []byte(password))
|
||||
return err == nil
|
||||
}
|
||||
Reference in New Issue
Block a user