Inital version. Authentication ready.

pull/2/head
Nilo Roberto da Cruz Paim 2021-05-14 15:56:46 -03:00
commit de3c682194
9 changed files with 386 additions and 0 deletions

13
.env Normal file
View File

@ -0,0 +1,13 @@
# Mysql Live
#Used when creating a JWT. It can be anything.
API_SECRET=nyEX8BZ44KqTXeV2
API_PORT=8111
# DB configuration
DB_HOST=185.167.97.70
DB_DRIVER=mysql
DB_USER=root
DB_PASSWORD=@407S732nwPhon
DB_NAME=pcast
DB_PORT=3306

View File

@ -0,0 +1,162 @@
package controllers
import (
"api/database"
"api/models"
"api/utils"
"os"
"strconv"
"time"
"github.com/dgrijalva/jwt-go"
"github.com/gofiber/fiber/v2"
"golang.org/x/crypto/bcrypt"
)
func Hello(c *fiber.Ctx) error {
return c.SendString("Hello!")
}
func Login(c *fiber.Ctx) error {
var data map[string]string
if err := c.BodyParser(&data); err != nil {
return err
}
var user models.User
database.DB.Where("email = ?", data["email"]).First(&user)
if user.Id == 0 {
c.Status(fiber.StatusNotFound)
return c.JSON(fiber.Map{
"message": "User not found",
})
}
if err := bcrypt.CompareHashAndPassword(user.Password, []byte(data["password"])); err != nil {
c.Status(fiber.StatusBadRequest)
return c.JSON(fiber.Map{
"message": "Incorrect password",
})
}
claims := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.StandardClaims{
Issuer: strconv.Itoa(int(user.Id)),
ExpiresAt: time.Now().Add(time.Hour * 1).Unix(),
})
token, err := claims.SignedString([]byte(os.Getenv("API_SECRET")))
if err != nil {
c.Status(fiber.StatusInternalServerError)
return c.JSON(fiber.Map{
"message": "Could't login",
})
}
cookie := fiber.Cookie{
Name: "jwt",
Value: token,
Expires: time.Now().Add(time.Hour * 1),
HTTPOnly: true,
}
c.Cookie(&cookie)
return c.JSON(token)
}
func Logout(c *fiber.Ctx) error {
cookie := fiber.Cookie{
Name: "jwt",
Value: "",
Expires: time.Now().Add(-time.Hour),
HTTPOnly: true,
}
c.Cookie(&cookie)
return c.JSON(fiber.Map{
"message": "Successful logout",
})
}
func AddUser(c *fiber.Ctx) error {
var data map[string]string
if err := c.BodyParser(&data); err != nil {
return err
}
passwd, _ := utils.HashPassword(data["password"])
user := models.User{
Name: data["name"],
Email: data["email"],
Password: passwd,
UserType: data["usertype"],
Blocked: "N",
First: "S",
Cancelled: "N",
}
database.DB.Create(&user)
if user.Id == 0 {
return c.SendStatus(fiber.StatusFound)
}
c.SendStatus(fiber.StatusCreated)
return c.JSON(user)
}
func User(c *fiber.Ctx) error {
cookie := c.Cookies("jwt")
var user models.User
claims, err := utils.VerifyAuthentication(c, cookie)
if err != nil {
c.Status(fiber.StatusUnauthorized)
return c.JSON(fiber.Map{
"message": "Unauthenticated",
})
}
database.DB.Where("id = ?", claims.Issuer).First(&user)
if user.Id == 0 {
c.Status(fiber.StatusUnauthorized)
return c.JSON(fiber.Map{
"message": "Unauthenticated",
})
}
return c.JSON(user)
}
func Users(c *fiber.Ctx) error {
cookie := c.Cookies("jwt")
var user []models.User
_, err := utils.VerifyAuthentication(c, cookie)
if err != nil {
c.Status(fiber.StatusUnauthorized)
return c.JSON(fiber.Map{
"message": "Unauthenticated",
})
}
database.DB.Find(&user)
if len(user) == 0 {
c.Status(fiber.StatusUnauthorized)
return c.JSON(fiber.Map{
"message": "Unauthenticated",
})
}
return c.JSON(user)
}

53
database/database.go Normal file
View File

@ -0,0 +1,53 @@
package database
import (
"api/models"
"fmt"
"log"
"os"
"github.com/joho/godotenv"
"gorm.io/driver/mysql"
"gorm.io/gorm"
"gorm.io/gorm/logger"
)
// Our database
var DB *gorm.DB
// NewDatabase - returns a pointer to a new database connection
func ConnectDB() error {
var erre error
log.Println("Getting environment values")
erre = godotenv.Load()
if erre != nil {
log.Printf("Error getting env, not comming through %v\n", erre)
return erre
}
DBURL := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8&parseTime=True&loc=Local", os.Getenv("DB_USER"), os.Getenv("DB_PASSWORD"), os.Getenv("DB_HOST"), os.Getenv("DB_PORT"), os.Getenv("DB_NAME"))
log.Println("Opening connection to database")
db, err := gorm.Open(mysql.Open(DBURL), &gorm.Config{
Logger: logger.Default.LogMode(logger.Silent),
})
if err != nil {
return err
}
if result := db.AutoMigrate(&models.User{}); result != nil {
return err
}
// if result := db.AutoMigrate(&models.Event{}); result != nil {
// return result
// }
DB = db
return nil
}

17
go.mod Normal file
View File

@ -0,0 +1,17 @@
module api
go 1.16
require (
github.com/andybalholm/brotli v1.0.2 // indirect
github.com/dgrijalva/jwt-go v3.2.0+incompatible // indirect
github.com/gofiber/fiber/v2 v2.9.0
github.com/joho/godotenv v1.3.0
github.com/klauspost/compress v1.12.2 // indirect
github.com/valyala/fasthttp v1.24.0 // indirect
github.com/valyala/tcplisten v1.0.0 // indirect
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a // indirect
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 // indirect
gorm.io/driver/mysql v1.0.6
gorm.io/gorm v1.21.9
)

51
go.sum Normal file
View File

@ -0,0 +1,51 @@
github.com/andybalholm/brotli v1.0.1/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/andybalholm/brotli v1.0.2 h1:JKnhI/XQ75uFBTiuzXpzFrUriDPiZjlOSzh6wXogP0E=
github.com/andybalholm/brotli v1.0.2/go.mod h1:loMXtMfwqflxFJPmdbJO0a3KNoPuLBgiu3qAvBg8x/Y=
github.com/dgrijalva/jwt-go v3.2.0+incompatible h1:7qlOGliEKZXTDg6OTjfoBKDXWrumCAMpl/TFQ4/5kLM=
github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ=
github.com/go-sql-driver/mysql v1.6.0 h1:BCTh4TKNUYmOmMUcQ3IipzF5prigylS7XXjEkfCHuOE=
github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg=
github.com/gofiber/fiber/v2 v2.9.0 h1:sZsTKlbyGGZ0UdTUn3ItQv5J9FTQUc4J3OS+03lE5m0=
github.com/gofiber/fiber/v2 v2.9.0/go.mod h1:Ah3IJikrKNRepl/HuVawppS25X7FWohwfCSRn7kJG28=
github.com/golang/snappy v0.0.3/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
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.2 h1:eVKgfIdy9b6zbWBMgFpfDPoAMifwSZagU9HmEU6zgiI=
github.com/jinzhu/now v1.1.2/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8=
github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc=
github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg=
github.com/klauspost/compress v1.11.8/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.11.13/go.mod h1:aoV0uJVorq1K+umq18yTdKaF57EivdYsUV+/s2qKfXs=
github.com/klauspost/compress v1.12.2 h1:2KCfW3I9M7nSc5wOqXAlW2v2U6v+w6cbjvbfp+OykW8=
github.com/klauspost/compress v1.12.2/go.mod h1:8dP1Hq4DHOhN9w426knH3Rhby4rFm6D8eO+e+Dq5Gzg=
github.com/valyala/bytebufferpool v1.0.0 h1:GqA5TC/0021Y/b9FG4Oi9Mr3q7XYx6KllzawFIhcdPw=
github.com/valyala/bytebufferpool v1.0.0/go.mod h1:6bBcMArwyJ5K/AmCkWv1jt77kVWyCJ6HpOuEn7z0Csc=
github.com/valyala/fasthttp v1.23.0/go.mod h1:0mw2RjXGOzxf4NL2jni3gUQ7LfjjUSiG5sskOUUSEpU=
github.com/valyala/fasthttp v1.24.0 h1:AAiG4oLDUArTb7rYf9oO2bkGooOqCaUF6a2u8asBP3I=
github.com/valyala/fasthttp v1.24.0/go.mod h1:0mw2RjXGOzxf4NL2jni3gUQ7LfjjUSiG5sskOUUSEpU=
github.com/valyala/tcplisten v0.0.0-20161114210144-ceec8f93295a/go.mod h1:v3UYOV9WzVtRmSR+PDvWpU/qWl4Wa5LApYYX4ZtKbio=
github.com/valyala/tcplisten v1.0.0 h1:rBHj/Xf+E1tRGZyWIWwJDiRY0zc1Js+CV5DqwacVSA8=
github.com/valyala/tcplisten v1.0.0/go.mod h1:T0xQ8SeCZGxckz9qRXTfG43PvQ/mcWh7FwZEA7Ioqkc=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20210220033148-5ea612d1eb83/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a h1:kr2P4QFmQr29mSLA43kwrOcgcReGTfbE9N577tCTuBc=
golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20210226101413-39120d07d75e/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210225134936-a50acf3fe073/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015 h1:hZR0X1kPW+nwyJ9xRxqZk1vx5RUObAPBdKVvXPDUH/E=
golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
gorm.io/driver/mysql v1.0.6 h1:mA0XRPjIKi4bkE9nv+NKs6qj6QWOchqUSdWOcpd3x1E=
gorm.io/driver/mysql v1.0.6/go.mod h1:KdrTanmfLPPyAOeYGyG+UpDys7/7eeWT1zCq+oekYnU=
gorm.io/gorm v1.21.9 h1:INieZtn4P2Pw6xPJ8MzT0G4WUOsHq3RhfuDF1M6GW0E=
gorm.io/gorm v1.21.9/go.mod h1:F+OptMscr0P2F2qU97WT1WimdH9GaQPoDW7AYd5i2Y0=

31
main.go Normal file
View File

@ -0,0 +1,31 @@
package main
import (
"api/database"
"api/routes"
"log"
"os"
"github.com/gofiber/fiber/v2"
"github.com/gofiber/fiber/v2/middleware/cors"
)
func main() {
app := fiber.New(fiber.Config{
StrictRouting: true,
DisableStartupMessage: true,
})
app.Use(cors.New(cors.Config{
AllowCredentials: true,
}))
if err := database.ConnectDB(); err != nil {
panic("Could not connect to database")
}
routes.Setup(app)
log.Println("Server started in port " + os.Getenv("API_PORT"))
app.Listen(":" + os.Getenv("API_PORT"))
}

12
models/users.go Normal file
View File

@ -0,0 +1,12 @@
package models
type User struct {
Id uint `gorm:"primary key" json:"id"`
Name string `gorm:"size:40;not null" json:"name"`
Email string `gorm:"size:40;not null;unique" json:"email"`
Password []byte `gorm:"size:100;not null;" json:"-"`
UserType string `gorm:"size:1;not null;default:U" json:"usertype"`
Blocked string `gorm:"size:1;not null;default:N" json:"blocked"`
First string `gorm:"size:1;not null;default:S" json:"first"`
Cancelled string `gorm:"size:1;not null;default:N" json:"cancelled"`
}

19
routes/routes.go Normal file
View File

@ -0,0 +1,19 @@
package routes
import (
"api/controllers"
"github.com/gofiber/fiber/v2"
)
func Setup(app *fiber.App) {
app.Post("/login", controllers.Login)
app.Post("/logout", controllers.Logout)
app.Get("/user", controllers.User)
app.Get("/users", controllers.Users)
app.Post("/user", controllers.AddUser)
app.Get("/", controllers.Hello)
}

28
utils/utils.go Normal file
View File

@ -0,0 +1,28 @@
package utils
import (
"os"
"github.com/dgrijalva/jwt-go"
"github.com/gofiber/fiber/v2"
"golang.org/x/crypto/bcrypt"
)
func HashPassword(password string) ([]byte, error) {
return bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
}
func VerifyAuthentication(c *fiber.Ctx, cookie string) (*jwt.StandardClaims, error) {
token, err := jwt.ParseWithClaims(cookie, &jwt.StandardClaims{}, func(token *jwt.Token) (interface{}, error) {
return []byte(os.Getenv("API_SECRET")), nil
})
if err != nil {
return nil, err
}
claims := token.Claims.(*jwt.StandardClaims)
return claims, nil
}