mirror of
https://github.com/wisplite/raster.git
synced 2026-05-01 06:32:44 -05:00
add basic auth with uuid-based access tokens
This commit is contained in:
@@ -20,6 +20,8 @@ func Init() bool {
|
|||||||
// Run migrations
|
// Run migrations
|
||||||
err = database.AutoMigrate(
|
err = database.AutoMigrate(
|
||||||
&models.Album{},
|
&models.Album{},
|
||||||
|
&models.User{},
|
||||||
|
&models.AccessToken{},
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal("failed to migrate database: ", err)
|
log.Fatal("failed to migrate database: ", err)
|
||||||
|
|||||||
@@ -0,0 +1,9 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type AccessToken struct {
|
||||||
|
Token string `gorm:"primaryKey"`
|
||||||
|
UserID string `gorm:"not null"`
|
||||||
|
Expires time.Time `gorm:"not null"`
|
||||||
|
}
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
package models
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
ID string `gorm:"primaryKey"`
|
||||||
|
Username string `gorm:"not null"`
|
||||||
|
Password string `gorm:"not null"`
|
||||||
|
IsAdmin bool `gorm:"not null"`
|
||||||
|
CreatedAt time.Time
|
||||||
|
UpdatedAt time.Time
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
package routes
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/gin-gonic/gin"
|
||||||
|
"github.com/wisplite/raster/internal/services"
|
||||||
|
)
|
||||||
|
|
||||||
|
func RegisterUserRoutes(rg *gin.RouterGroup) {
|
||||||
|
user := rg.Group("/user")
|
||||||
|
user.POST("/createUser", func(c *gin.Context) {
|
||||||
|
username := c.PostForm("username")
|
||||||
|
password := c.PostForm("password")
|
||||||
|
err := services.CreateUser(username, password)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, gin.H{"message": "User created successfully"})
|
||||||
|
})
|
||||||
|
user.POST("/login", func(c *gin.Context) {
|
||||||
|
username := c.PostForm("username")
|
||||||
|
password := c.PostForm("password")
|
||||||
|
accessToken, err := services.Login(username, password)
|
||||||
|
if err != nil {
|
||||||
|
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.JSON(http.StatusOK, gin.H{"message": "Login successful", "accessToken": accessToken.Token})
|
||||||
|
})
|
||||||
|
}
|
||||||
@@ -0,0 +1,24 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/google/uuid"
|
||||||
|
"github.com/wisplite/raster/internal/db"
|
||||||
|
"github.com/wisplite/raster/internal/models"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateAccessToken(userID string) (models.AccessToken, error) {
|
||||||
|
token := uuid.New().String()
|
||||||
|
expires := time.Now().Add(time.Hour * 24 * 30)
|
||||||
|
accessToken := models.AccessToken{
|
||||||
|
Token: token,
|
||||||
|
UserID: userID,
|
||||||
|
Expires: expires,
|
||||||
|
}
|
||||||
|
result := db.GetDB().Create(&accessToken)
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.AccessToken{}, result.Error
|
||||||
|
}
|
||||||
|
return accessToken, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
package services
|
||||||
|
|
||||||
|
import (
|
||||||
|
"log"
|
||||||
|
|
||||||
|
"github.com/wisplite/raster/internal/db"
|
||||||
|
"github.com/wisplite/raster/internal/models"
|
||||||
|
"golang.org/x/crypto/bcrypt"
|
||||||
|
)
|
||||||
|
|
||||||
|
func CreateUser(username string, password string) error {
|
||||||
|
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal("failed to hash password: ", err)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
user := models.User{
|
||||||
|
Username: username,
|
||||||
|
Password: string(hashedPassword),
|
||||||
|
IsAdmin: false,
|
||||||
|
}
|
||||||
|
result := db.GetDB().Create(&user)
|
||||||
|
if result.Error != nil {
|
||||||
|
return result.Error
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func Login(username string, password string) (models.AccessToken, error) {
|
||||||
|
user := models.User{}
|
||||||
|
result := db.GetDB().First(&user, "username = ?", username)
|
||||||
|
if result.Error != nil {
|
||||||
|
return models.AccessToken{}, result.Error
|
||||||
|
}
|
||||||
|
err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password))
|
||||||
|
if err != nil {
|
||||||
|
return models.AccessToken{}, err
|
||||||
|
}
|
||||||
|
accessToken, err := CreateAccessToken(user.ID)
|
||||||
|
if err != nil {
|
||||||
|
return models.AccessToken{}, err
|
||||||
|
}
|
||||||
|
return accessToken, nil
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user