feat: replace placeholder auth with db hash

This commit is contained in:
2026-01-14 13:44:26 +01:00
parent b706a9ce14
commit bf913012ac
3 changed files with 89 additions and 6 deletions
+66 -6
View File
@@ -14,6 +14,7 @@ import (
"github.com/gin-gonic/gin"
"github.com/golang-jwt/jwt/v5"
"github.com/google/uuid"
"golang.org/x/crypto/bcrypt"
)
type Handler struct {
@@ -93,7 +94,7 @@ func (h *Handler) Hello(c *gin.Context) {
c.JSON(http.StatusOK, gin.H{"message": "hello from lambdaiot"})
}
// Login issues a JWT token for demo purposes
// Login issues a JWT token after validating credentials against the database
func (h *Handler) Login(c *gin.Context) {
var req struct {
Username string `json:"username"`
@@ -103,15 +104,31 @@ func (h *Handler) Login(c *gin.Context) {
c.JSON(http.StatusBadRequest, gin.H{"error": "invalid json"})
return
}
// demo credentials
if req.Username != "admin" || req.Password != "password" {
// Query user from database
var userID string
var passwordHash string
err := h.DB.QueryRow("SELECT BIN_TO_UUID(id), password_hash FROM users WHERE username = ?", req.Username).Scan(&userID, &passwordHash)
if err == sql.ErrNoRows {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
return
}
// create token
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "database error"})
return
}
// Verify password
if err := bcrypt.CompareHashAndPassword([]byte(passwordHash), []byte(req.Password)); err != nil {
c.JSON(http.StatusUnauthorized, gin.H{"error": "invalid credentials"})
return
}
// Create token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{
"sub": req.Username,
"exp": time.Now().Add(time.Hour).Unix(),
"sub": req.Username,
"user_id": userID,
"exp": time.Now().Add(24 * time.Hour).Unix(),
})
signed, err := token.SignedString([]byte(h.JWTSecret))
if err != nil {
@@ -841,3 +858,46 @@ func (h *Handler) DeleteSensorReading(c *gin.Context) {
}
c.JSON(http.StatusOK, gin.H{"message": "sensor reading deleted"})
}
// Register creates a new user account
func (h *Handler) Register(c *gin.Context) {
var req struct {
Username string `json:"username" binding:"required,min=3,max=50"`
Password string `json:"password" binding:"required,min=6"`
Email string `json:"email"`
}
if err := c.ShouldBindJSON(&req); err != nil {
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// Check if username already exists
var exists int
err := h.DB.QueryRow("SELECT COUNT(*) FROM users WHERE username = ?", req.Username).Scan(&exists)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "database error"})
return
}
if exists > 0 {
c.JSON(http.StatusConflict, gin.H{"error": "username already exists"})
return
}
// Hash password
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(req.Password), bcrypt.DefaultCost)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to hash password"})
return
}
// Insert user
userID := uuid.New()
_, err = h.DB.Exec("INSERT INTO users (id, username, password_hash, email) VALUES (UUID_TO_BIN(?), ?, ?, ?)",
userID.String(), req.Username, string(hashedPassword), req.Email)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "failed to create user"})
return
}
c.JSON(http.StatusCreated, gin.H{"id": userID.String(), "username": req.Username})
}