feat(auth): Implement database-backed user authentication and
persistence This commit introduces a major architectural change by replacing the previous hardcoded user and data system with a robust, database-driven approach. It lays the foundation for persistent data storage for all application models. Key Changes: - **Database Integration:** - Added `GORM` and `SQLite` for the database layer. - The database is now initialized and migrated on application startup. - Configuration is managed through environment variables (`DATABASE`, `USERS_FILE`). - **User Authentication & Management:** - The login endpoint (`/api/token`) now authenticates users against the database. - JWT claims are now populated with real user data (`id`, `username`, `is_superuser`). - Implemented a system to seed the database with initial users from a `users.json` file. - **New User API Endpoints:** - `GET /api/users`: Retrieves a list of all users (superuser access required). - `GET /api/users/user`: Fetches the data for the currently authenticated user based on their JWT. - **Data Model Overhaul:** - Refactored all data models (`User`, `Category`, `Operation`, `Subcategory`) to include GORM tags, relationships, and a `BaseModel` with auto-generated UUIDs for primary keys. - Separated user-related structs into `User` (database model), `AuthRequest` (login payload), and `UserResponse` (safe API response). - **Middleware & Routing:** - Improved JWT error handling for clearer client-side messages. - Added a new middleware to allow passing the JWT in the request body for more flexible client integration.
This commit is contained in:
@@ -1,2 +1,3 @@
|
||||
go.sum
|
||||
backend
|
||||
wallet.sqlite
|
||||
|
||||
@@ -1,17 +0,0 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/golang-jwt/jwt"
|
||||
)
|
||||
|
||||
func Accessible(c *fiber.Ctx) error {
|
||||
return c.SendString("Accessible")
|
||||
}
|
||||
|
||||
func Restricted(c *fiber.Ctx) error {
|
||||
user := c.Locals("user").(*jwt.Token)
|
||||
claims := user.Claims.(jwt.MapClaims)
|
||||
name := claims["name"].(string)
|
||||
return c.SendString("Welcome " + name)
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"backend/database"
|
||||
"backend/model"
|
||||
"fmt"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
func GetAllUsers(c *fiber.Ctx) error {
|
||||
user := c.Locals("user").(*jwt.Token)
|
||||
claims := user.Claims.(jwt.MapClaims)
|
||||
userid := claims["id"].(string)
|
||||
|
||||
dbuser, e := database.GetUserById(userid)
|
||||
if e != nil {
|
||||
return c.Status(
|
||||
fiber.StatusInternalServerError,
|
||||
).JSON(
|
||||
fiber.Map{
|
||||
"error": e.Error(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if !dbuser.IsSuperuser {
|
||||
return c.Status(
|
||||
fiber.StatusForbidden,
|
||||
).JSON(
|
||||
fiber.Map{
|
||||
"error": "you are not superuser",
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
users, e := database.GetAllUsers()
|
||||
if e != nil {
|
||||
return fmt.Errorf("Error: %v", e)
|
||||
}
|
||||
var responseUsers []model.UserResponse
|
||||
for i := range users {
|
||||
responseUsers = append(
|
||||
responseUsers,
|
||||
model.UserResponse{
|
||||
ID: users[i].ID,
|
||||
Username: users[i].Username,
|
||||
Email: users[i].Email,
|
||||
Group: users[i].Group,
|
||||
IsSuperuser: users[i].IsSuperuser,
|
||||
},
|
||||
)
|
||||
}
|
||||
return c.JSON(responseUsers)
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"backend/database"
|
||||
"backend/model"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
func GetUserData(c *fiber.Ctx) error {
|
||||
user := c.Locals("user").(*jwt.Token)
|
||||
claims := user.Claims.(jwt.MapClaims)
|
||||
userid := claims["id"].(string)
|
||||
|
||||
dbuser, e := database.GetUserById(userid)
|
||||
if e != nil {
|
||||
return c.Status(
|
||||
fiber.StatusInternalServerError,
|
||||
).JSON(
|
||||
fiber.Map{
|
||||
"error": e.Error(),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
return c.JSON(model.UserResponse{
|
||||
ID: dbuser.ID,
|
||||
Username: dbuser.Username,
|
||||
Email: dbuser.Email,
|
||||
Group: dbuser.Group,
|
||||
IsSuperuser: dbuser.IsSuperuser,
|
||||
})
|
||||
}
|
||||
+11
-5
@@ -1,13 +1,14 @@
|
||||
package api
|
||||
|
||||
import (
|
||||
"backend/database"
|
||||
"backend/model"
|
||||
"fmt"
|
||||
"os"
|
||||
"time"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
"github.com/golang-jwt/jwt"
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
)
|
||||
|
||||
func Login(c *fiber.Ctx) error {
|
||||
@@ -16,13 +17,18 @@ func Login(c *fiber.Ctx) error {
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error parse body, %s", err)
|
||||
}
|
||||
if requestdata.Username != "tola" || requestdata.Password != "2808" {
|
||||
return c.SendStatus(fiber.StatusUnauthorized)
|
||||
dbuser, e := database.GetUserByUsername(requestdata.Username)
|
||||
if e != nil {
|
||||
return fiber.ErrInternalServerError
|
||||
}
|
||||
if dbuser.Password != requestdata.Password {
|
||||
return fiber.ErrForbidden
|
||||
}
|
||||
|
||||
claims := jwt.MapClaims{
|
||||
"username": "tola",
|
||||
"is_superuser": true,
|
||||
"id": dbuser.ID,
|
||||
"username": dbuser.Username,
|
||||
"is_superuser": dbuser.IsSuperuser,
|
||||
"exp": time.Now().Add(time.Hour * 72).Unix(),
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"backend/model"
|
||||
"os"
|
||||
|
||||
"github.com/glebarez/sqlite"
|
||||
"github.com/gofiber/fiber/v2/log"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
var Db *gorm.DB
|
||||
|
||||
func Init() error {
|
||||
if os.Getenv("DATABASE") == "" {
|
||||
log.Fatal("Error no DATABASE path or url")
|
||||
}
|
||||
var err error
|
||||
Db, err = gorm.Open(sqlite.Open(os.Getenv("DATABASE")), &gorm.Config{})
|
||||
if err != nil {
|
||||
log.Error("Failed to connect database")
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func Migrate() {
|
||||
Db.AutoMigrate(
|
||||
&model.User{},
|
||||
&model.Category{},
|
||||
&model.Subcategory{},
|
||||
&model.Operation{},
|
||||
)
|
||||
}
|
||||
|
||||
func InitDatabase() {
|
||||
Init()
|
||||
Migrate()
|
||||
|
||||
if os.Getenv("USERS_FILE") != "" {
|
||||
allusers := GetUsersFromFile(os.Getenv("USERS_FILE"))
|
||||
for i := range allusers {
|
||||
CreateUser(&allusers[i])
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
package database
|
||||
|
||||
import (
|
||||
"backend/model"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
func CreateUser(user *model.User) error {
|
||||
e := Db.Where(model.User{
|
||||
Username: user.Username,
|
||||
}).FirstOrCreate(&user).Error
|
||||
if e != nil {
|
||||
return e
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetUserById(id string) (*model.User, error) {
|
||||
var user model.User
|
||||
e := Db.First(&user, "id = ?", id).Error
|
||||
if e != nil {
|
||||
if errors.Is(e, gorm.ErrRecordNotFound) {
|
||||
return nil, fmt.Errorf("user not found")
|
||||
}
|
||||
return nil, e
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func GetUserByUsername(username string) (*model.User, error) {
|
||||
var user model.User
|
||||
e := Db.First(&user, "username = ?", username).Error
|
||||
if e != nil {
|
||||
if errors.Is(e, gorm.ErrRecordNotFound) {
|
||||
return nil, fmt.Errorf("user not found")
|
||||
}
|
||||
return nil, e
|
||||
}
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
func DeleteUser(id string) error {
|
||||
var user model.User
|
||||
e := Db.First(&user, "id = ?", id).Error
|
||||
if e != nil {
|
||||
if errors.Is(e, gorm.ErrRecordNotFound) {
|
||||
return fmt.Errorf("user not found")
|
||||
}
|
||||
return e
|
||||
}
|
||||
e = Db.Unscoped().Delete(&user).Error
|
||||
if e != nil {
|
||||
if errors.Is(e, gorm.ErrRecordNotFound) {
|
||||
return fmt.Errorf("user not found")
|
||||
}
|
||||
return e
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func GetUsersFromFile(filename string) []model.User {
|
||||
data, e := os.ReadFile(filename)
|
||||
if e != nil {
|
||||
panic(e)
|
||||
}
|
||||
decoder := json.NewDecoder(strings.NewReader(string(data)))
|
||||
var res []model.User
|
||||
decoder.Decode(&res)
|
||||
return res
|
||||
}
|
||||
|
||||
func GetAllUsers() ([]model.User, error) {
|
||||
var users []model.User
|
||||
e := Db.Find(&users).Error
|
||||
if e != nil {
|
||||
return nil, e
|
||||
}
|
||||
return users, nil
|
||||
}
|
||||
+13
-1
@@ -3,24 +3,36 @@ module backend
|
||||
go 1.24.5
|
||||
|
||||
require (
|
||||
github.com/glebarez/sqlite v1.11.0
|
||||
github.com/gofiber/contrib/jwt v1.1.2
|
||||
github.com/gofiber/fiber/v2 v2.52.9
|
||||
github.com/golang-jwt/jwt v3.2.2+incompatible
|
||||
github.com/google/uuid v1.6.0
|
||||
github.com/joho/godotenv v1.5.1
|
||||
gorm.io/gorm v1.30.1
|
||||
)
|
||||
|
||||
require (
|
||||
github.com/MicahParks/keyfunc/v2 v2.1.0 // indirect
|
||||
github.com/andybalholm/brotli v1.1.0 // indirect
|
||||
github.com/dustin/go-humanize v1.0.1 // indirect
|
||||
github.com/glebarez/go-sqlite v1.21.2 // indirect
|
||||
github.com/golang-jwt/jwt/v5 v5.2.2 // indirect
|
||||
github.com/google/uuid v1.6.0 // indirect
|
||||
github.com/jinzhu/inflection v1.0.0 // indirect
|
||||
github.com/jinzhu/now v1.1.5 // indirect
|
||||
github.com/klauspost/compress v1.17.9 // indirect
|
||||
github.com/mattn/go-colorable v0.1.13 // indirect
|
||||
github.com/mattn/go-isatty v0.0.20 // indirect
|
||||
github.com/mattn/go-runewidth v0.0.16 // indirect
|
||||
github.com/remyoudompheng/bigfft v0.0.0-20230129092748-24d4a6f8daec // indirect
|
||||
github.com/rivo/uniseg v0.2.0 // indirect
|
||||
github.com/valyala/bytebufferpool v1.0.0 // indirect
|
||||
github.com/valyala/fasthttp v1.51.0 // indirect
|
||||
github.com/valyala/tcplisten v1.0.0 // indirect
|
||||
golang.org/x/sys v0.28.0 // indirect
|
||||
golang.org/x/text v0.20.0 // indirect
|
||||
modernc.org/libc v1.22.5 // indirect
|
||||
modernc.org/mathutil v1.5.0 // indirect
|
||||
modernc.org/memory v1.5.0 // indirect
|
||||
modernc.org/sqlite v1.23.1 // indirect
|
||||
)
|
||||
|
||||
@@ -5,41 +5,34 @@ import "backend/model"
|
||||
func GetAllCategories() ([]model.Category, error) {
|
||||
return []model.Category{
|
||||
{
|
||||
ID: "1",
|
||||
Title: "Electronics",
|
||||
Icon: "😀",
|
||||
Type: "expense",
|
||||
},
|
||||
{
|
||||
ID: "2",
|
||||
Title: "Clothing",
|
||||
Icon: "😁",
|
||||
Type: "expense",
|
||||
},
|
||||
{
|
||||
ID: "3",
|
||||
Title: "Books",
|
||||
Icon: "😂",
|
||||
Subcategories: []model.Subcategory{
|
||||
{
|
||||
ID: "1",
|
||||
Title: "Fiction",
|
||||
},
|
||||
{
|
||||
ID: "2",
|
||||
Title: "Non-Fiction",
|
||||
},
|
||||
},
|
||||
Type: "expense",
|
||||
},
|
||||
{
|
||||
ID: "4",
|
||||
Title: "Salary",
|
||||
Icon: "😀",
|
||||
Type: "income",
|
||||
},
|
||||
{
|
||||
ID: "5",
|
||||
Title: "asdf",
|
||||
Icon: "😀",
|
||||
Type: "income",
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package internaljwt
|
||||
|
||||
import (
|
||||
"backend/model"
|
||||
|
||||
"github.com/gofiber/fiber/v2"
|
||||
)
|
||||
|
||||
func JwtFromBody(c *fiber.Ctx) error {
|
||||
req := new(model.TokenRequest)
|
||||
if err := c.BodyParser(req); err != nil {
|
||||
return c.Status(
|
||||
fiber.StatusBadRequest,
|
||||
).JSON(
|
||||
fiber.Map{
|
||||
"error": "Cannot parse request body",
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
if req.Token == "" {
|
||||
return c.Status(
|
||||
fiber.StatusBadRequest,
|
||||
).JSON(
|
||||
fiber.Map{
|
||||
"error": "Token not found in request body",
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
c.Request().Header.Set(
|
||||
"Authorization", "Bearer "+req.Token,
|
||||
)
|
||||
|
||||
return c.Next()
|
||||
}
|
||||
@@ -8,12 +8,13 @@ import (
|
||||
func GetAllOperation() ([]model.Operation, error) {
|
||||
return []model.Operation{
|
||||
{
|
||||
ID: "1",
|
||||
Title: "Operation 1",
|
||||
Amount: 100,
|
||||
Category: "Category 1",
|
||||
SubCategory: model.Subcategory{
|
||||
ID: "1",
|
||||
Title: "Operation 1",
|
||||
Amount: 100,
|
||||
Category: model.Category{
|
||||
Title: "category 1",
|
||||
Type: "income",
|
||||
},
|
||||
Subcategory: model.Subcategory{
|
||||
Title: "subcategory",
|
||||
},
|
||||
Date: "2022-01-01T00:00:00Z",
|
||||
@@ -21,30 +22,35 @@ func GetAllOperation() ([]model.Operation, error) {
|
||||
Icon: "😀",
|
||||
},
|
||||
{
|
||||
ID: "2",
|
||||
Title: "Operation 2",
|
||||
Amount: 200,
|
||||
Category: "Category 2",
|
||||
Date: "2022-01-02T00:00:00Z",
|
||||
Type: "expense",
|
||||
Icon: "😂",
|
||||
Title: "Operation 2",
|
||||
Amount: 200,
|
||||
Category: model.Category{
|
||||
Title: "Category 2",
|
||||
Type: "expense",
|
||||
},
|
||||
Date: "2022-01-02T00:00:00Z",
|
||||
Type: "expense",
|
||||
Icon: "😂",
|
||||
},
|
||||
{
|
||||
ID: "2",
|
||||
Title: "Operation 2",
|
||||
Amount: 200,
|
||||
Category: "Category 2",
|
||||
Date: time.Now().Format(time.RFC3339),
|
||||
Type: "expense",
|
||||
Icon: "😂",
|
||||
Title: "Operation 2",
|
||||
Amount: 200,
|
||||
Category: model.Category{
|
||||
Title: "Category 2",
|
||||
Type: "expense",
|
||||
},
|
||||
Date: time.Now().Format(time.RFC3339),
|
||||
Type: "expense",
|
||||
Icon: "😂",
|
||||
},
|
||||
{
|
||||
ID: "1",
|
||||
Title: "Operation 1",
|
||||
Amount: 100,
|
||||
Category: "Category 1",
|
||||
SubCategory: model.Subcategory{
|
||||
ID: "1",
|
||||
Title: "Operation 1",
|
||||
Amount: 100,
|
||||
Category: model.Category{
|
||||
Title: "Category 2",
|
||||
Type: "expense",
|
||||
},
|
||||
Subcategory: model.Subcategory{
|
||||
Title: "subcategory",
|
||||
},
|
||||
Date: "2022-01-02T00:00:00Z",
|
||||
@@ -52,22 +58,26 @@ func GetAllOperation() ([]model.Operation, error) {
|
||||
Icon: "😀",
|
||||
},
|
||||
{
|
||||
ID: "2",
|
||||
Title: "Operation 2",
|
||||
Amount: 200,
|
||||
Category: "Category 2",
|
||||
Date: "2022-06-02T00:00:00Z",
|
||||
Type: "expense",
|
||||
Icon: "😂",
|
||||
Title: "Operation 2",
|
||||
Amount: 200,
|
||||
Category: model.Category{
|
||||
Title: "Category 2",
|
||||
Type: "expense",
|
||||
},
|
||||
Date: "2022-06-02T00:00:00Z",
|
||||
Type: "expense",
|
||||
Icon: "😂",
|
||||
},
|
||||
{
|
||||
ID: "2",
|
||||
Title: "Operation 2",
|
||||
Amount: 200,
|
||||
Category: "Category 2",
|
||||
Date: "2022-06-22T00:00:00Z",
|
||||
Type: "expense",
|
||||
Icon: "😂",
|
||||
Title: "Operation 2",
|
||||
Amount: 200,
|
||||
Category: model.Category{
|
||||
Title: "Category 2",
|
||||
Type: "expense",
|
||||
},
|
||||
Date: "2022-06-22T00:00:00Z",
|
||||
Type: "expense",
|
||||
Icon: "😂",
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package model
|
||||
|
||||
import (
|
||||
"github.com/google/uuid"
|
||||
"gorm.io/gorm"
|
||||
)
|
||||
|
||||
type BaseModel struct {
|
||||
ID string `json:"id" gorm:"primaryKey"`
|
||||
}
|
||||
|
||||
func (base *BaseModel) BeforeCreate(tx *gorm.DB) (err error) {
|
||||
// generate new uuid if ID not created yet
|
||||
if base.ID == "" {
|
||||
base.ID = uuid.New().String()
|
||||
}
|
||||
return
|
||||
}
|
||||
@@ -1,9 +1,10 @@
|
||||
package model
|
||||
|
||||
type Category struct {
|
||||
ID string `json:"id"`
|
||||
BaseModel
|
||||
Icon string `json:"icon"`
|
||||
Title string `json:"title"`
|
||||
Subcategories []Subcategory `json:"subcategories"`
|
||||
Subcategories []Subcategory `json:"subcategories" gorm:"foreignKey:CategoryID"`
|
||||
Type string `json:"type"`
|
||||
UserID string
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package model
|
||||
|
||||
type Operation struct {
|
||||
BaseModel
|
||||
Title string `json:"title"`
|
||||
Amount float64 `json:"amount"`
|
||||
Note string `json:"note,omitempty"`
|
||||
Icon string `json:"icon"`
|
||||
Type string `json:"type"`
|
||||
Date string `json:"date"`
|
||||
UserID string
|
||||
CategoryID string
|
||||
SubcategoryID string
|
||||
Category Category `gorm:"foreignKey:CategoryID"`
|
||||
Subcategory Subcategory `gorm:"foreignKey:SubcategoryID"`
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package model
|
||||
|
||||
type Subcategory struct {
|
||||
BaseModel
|
||||
Title string `json:"title"`
|
||||
CategoryID string
|
||||
UserID string
|
||||
}
|
||||
@@ -0,0 +1,5 @@
|
||||
package model
|
||||
|
||||
type TokenRequest struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package model
|
||||
|
||||
type User struct {
|
||||
BaseModel
|
||||
Username string `json:"username" gorm:"unique"`
|
||||
Email string `json:"email" gorm:"unique"`
|
||||
Password string `json:"password"`
|
||||
Group string `json:"group"`
|
||||
IsSuperuser bool `json:"is_superuser"`
|
||||
Categories []Category `json:"categories" gorm:"foreignKey:UserID"`
|
||||
Subcategories []Subcategory `json:"subcategories" gorm:"foreignKey:UserID"`
|
||||
Operations []Operation `json:"operations" gorm:"foreignKey:UserID"`
|
||||
}
|
||||
|
||||
type AuthRequest struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type UserResponse struct {
|
||||
ID string `json:"id"`
|
||||
Username string `json:"username"`
|
||||
Email string `json:"email"`
|
||||
Group string `json:"group"`
|
||||
IsSuperuser bool `json:"is_superuser"`
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package model
|
||||
|
||||
type Operation struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
Amount float64 `json:"amount"`
|
||||
Category string `json:"category"`
|
||||
SubCategory Subcategory `json:"subcategory,omitzero"`
|
||||
Note string `json:"note,omitempty"`
|
||||
Icon string `json:"icon"`
|
||||
Type string `json:"type"`
|
||||
Date string `json:"date"`
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package model
|
||||
|
||||
type Subcategory struct {
|
||||
ID string `json:"id"`
|
||||
Title string `json:"title"`
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package model
|
||||
|
||||
type AuthRequest struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
}
|
||||
|
||||
type User struct {
|
||||
Username string `json:"username"`
|
||||
Password string `json:"password"`
|
||||
Email string `json:"email"`
|
||||
Group string `json:"group"`
|
||||
IsSuperuser bool `json:"is_superuser"`
|
||||
}
|
||||
@@ -2,6 +2,8 @@ package server
|
||||
|
||||
import (
|
||||
"backend/api"
|
||||
"backend/database"
|
||||
"backend/internal/internaljwt"
|
||||
"backend/utils"
|
||||
"os"
|
||||
|
||||
@@ -13,6 +15,7 @@ import (
|
||||
|
||||
func Configure(app *fiber.App) {
|
||||
utils.LoadEnv("wallet.conf")
|
||||
database.InitDatabase()
|
||||
log.SetLevel(log.LevelDebug)
|
||||
app.Use(cors.New(cors.Config{
|
||||
AllowOrigins: "http://localhost:3000",
|
||||
@@ -22,13 +25,39 @@ func Configure(app *fiber.App) {
|
||||
apiGroup := app.Group("/api")
|
||||
|
||||
apiGroup.Post("/token", api.Login)
|
||||
apiGroup.Get("/accessible", api.Accessible)
|
||||
app.Use(jwtware.New(jwtware.Config{
|
||||
app.Use(internaljwt.JwtFromBody, jwtware.New(jwtware.Config{
|
||||
SigningKey: jwtware.SigningKey{
|
||||
Key: []byte(os.Getenv("JWT_SECRET_KEY")),
|
||||
},
|
||||
ErrorHandler: func(c *fiber.Ctx, err error) error {
|
||||
if err.Error() == "Missing or malformed JWT" {
|
||||
return c.Status(
|
||||
fiber.StatusBadRequest,
|
||||
).JSON(
|
||||
fiber.Map{
|
||||
"status": "error",
|
||||
"message": "Missing or malformed JWT",
|
||||
"data": nil,
|
||||
},
|
||||
)
|
||||
}
|
||||
return c.Status(
|
||||
fiber.StatusUnauthorized,
|
||||
).JSON(
|
||||
fiber.Map{
|
||||
"status": "error",
|
||||
"message": "Invalid or expired JWT",
|
||||
"data": nil,
|
||||
"error": err.Error(),
|
||||
},
|
||||
)
|
||||
},
|
||||
}))
|
||||
apiGroup.Get("/rescticted", api.Restricted)
|
||||
|
||||
usersGroup := apiGroup.Group("/users")
|
||||
usersGroup.Get("/", api.GetAllUsers)
|
||||
usersGroup.Get("/user", api.GetUserData)
|
||||
|
||||
operationGroup := apiGroup.Group("/operation")
|
||||
operationGroup.Get("/", api.GetAllOperation)
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
[
|
||||
{
|
||||
"username": "tola",
|
||||
"email": "mail@example.com",
|
||||
"password": "2808",
|
||||
"group": "root",
|
||||
"is_superuser": true
|
||||
},
|
||||
{
|
||||
"username": "lisa",
|
||||
"email": "lisa@example.com",
|
||||
"password": "asdf",
|
||||
"group": "users",
|
||||
"is_superuser": false
|
||||
}
|
||||
]
|
||||
@@ -3,3 +3,5 @@ HTTP_ADDRESS=0.0.0.0:43243
|
||||
ENABLE_TLS=true
|
||||
CERT_FILE=/home/tola/certs/localhost/localhost.crt
|
||||
KEY_FILE=/home/tola/certs/localhost/localhost.key
|
||||
USERS_FILE=users.json
|
||||
DATABASE=wallet.sqlite
|
||||
|
||||
Reference in New Issue
Block a user