You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
63 lines
1.6 KiB
63 lines
1.6 KiB
package auth
|
|
|
|
import (
|
|
"encoding/json"
|
|
"net/http"
|
|
|
|
"github.com/jackc/pgx/v5/pgxpool"
|
|
)
|
|
|
|
type loginRequest struct {
|
|
Username string `json:"username"`
|
|
Password string `json:"password"`
|
|
}
|
|
|
|
type userResponse struct {
|
|
ID int64 `json:"id"`
|
|
Username string `json:"username"`
|
|
Role string `json:"role"`
|
|
}
|
|
|
|
type loginResponse struct {
|
|
Token string `json:"token"`
|
|
User userResponse `json:"user"`
|
|
}
|
|
|
|
// NewLoginHandler returns the handler for POST /api/auth/login.
|
|
func NewLoginHandler(db *pgxpool.Pool, jwtSecret string) http.HandlerFunc {
|
|
return func(w http.ResponseWriter, r *http.Request) {
|
|
var req loginRequest
|
|
if err := json.NewDecoder(r.Body).Decode(&req); err != nil || req.Username == "" || req.Password == "" {
|
|
http.Error(w, "invalid input", http.StatusBadRequest)
|
|
return
|
|
}
|
|
|
|
var id int64
|
|
var username, role, passwordHash string
|
|
err := db.QueryRow(r.Context(),
|
|
`SELECT id, username, role, password FROM users WHERE username = $1`,
|
|
req.Username,
|
|
).Scan(&id, &username, &role, &passwordHash)
|
|
if err != nil {
|
|
http.Error(w, "invalid username or password", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
if err := VerifyPassword(passwordHash, req.Password); err != nil {
|
|
http.Error(w, "invalid username or password", http.StatusUnauthorized)
|
|
return
|
|
}
|
|
|
|
token, err := GenerateJWT(jwtSecret, id, username, role)
|
|
if err != nil {
|
|
http.Error(w, "internal server error", http.StatusInternalServerError)
|
|
return
|
|
}
|
|
|
|
w.Header().Set("Content-Type", "application/json")
|
|
json.NewEncoder(w).Encode(loginResponse{
|
|
Token: token,
|
|
User: userResponse{ID: id, Username: username, Role: role},
|
|
})
|
|
}
|
|
}
|
|
|