adding jwt tokens

This commit is contained in:
2025-11-25 16:03:05 +00:00
parent cc84ef6a13
commit 0466d9d288
8 changed files with 111 additions and 25 deletions

View File

@@ -4,7 +4,9 @@ go 1.24.0
require (
github.com/gin-gonic/gin v1.11.0
github.com/golang-jwt/jwt/v5 v5.3.0
github.com/zmb3/spotify/v2 v2.4.3
golang.org/x/crypto v0.43.0
golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5
gorm.io/driver/postgres v1.6.0
gorm.io/gorm v1.31.1
@@ -41,7 +43,6 @@ require (
github.com/ugorji/go/codec v1.3.0 // indirect
go.uber.org/mock v0.5.0 // indirect
golang.org/x/arch v0.20.0 // indirect
golang.org/x/crypto v0.43.0 // indirect
golang.org/x/mod v0.29.0 // indirect
golang.org/x/net v0.46.0 // indirect
golang.org/x/sync v0.17.0 // indirect

View File

@@ -73,6 +73,8 @@ github.com/goccy/go-json v0.10.2 h1:CrxCmQqYDkv1z7lO7Wbh2HN93uovUHgrECaO5ZrCXAU=
github.com/goccy/go-json v0.10.2/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-yaml v1.18.0 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo=
github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE=
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=

View File

@@ -1 +1,75 @@
package handlers
import (
"net/http"
"adam-french.co.uk/backend/models"
"github.com/gin-gonic/gin"
"golang.org/x/crypto/bcrypt"
)
type UserCredentials struct {
Username string `json:"username" binding:"required"`
Password string `json:"password" binding:"required"`
}
func (store *Store) CreateUser(ctx *gin.Context) {
var input UserCredentials
if err := ctx.ShouldBindBodyWithJSON(&input); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
hashedPassword, err := bcrypt.GenerateFromPassword([]byte(input.Password), bcrypt.DefaultCost)
if err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
user := models.User{Username: input.Username, Password: hashedPassword}
store.DB.Create(&user)
// Generate JWT token
ctx.JSON(http.StatusOK, gin.H{"data": user})
}
func (store *Store) LoginUser(ctx *gin.Context) {
var input UserCredentials
if err := ctx.ShouldBindBodyWithJSON(&input); err != nil {
ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
user := models.User{Username: input.Username}
if err := store.DB.Where("username = ?", input.Username).First(&user).Error; err != nil {
ctx.JSON(http.StatusNotFound, gin.H{"error": err.Error()})
return
}
if err := bcrypt.CompareHashAndPassword(user.Password, []byte(input.Password)); err != nil {
ctx.JSON(http.StatusUnauthorized, gin.H{"error": err.Error()})
return
}
// Generate JWT token
ctx.JSON(http.StatusAccepted, gin.H{"data": user})
}
func (store *Store) GetUser(ctx *gin.Context) {
}
func (store *Store) GetUsers(ctx *gin.Context) {
var users []models.User
if err := store.DB.Find(&users).Error; err != nil {
ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
ctx.JSON(http.StatusOK, gin.H{"data": models.Post{}})
}
func (store *Store) UpdateUser(c *gin.Context) {
}

View File

@@ -1,6 +1,7 @@
package handlers
import (
"adam-french.co.uk/backend/services"
"github.com/zmb3/spotify/v2"
spotifyauth "github.com/zmb3/spotify/v2/auth"
"gorm.io/gorm"
@@ -10,4 +11,5 @@ type Store struct {
DB *gorm.DB
SpotifyAuth *spotifyauth.Authenticator
SpotifyClient *spotify.Client
Auth *services.Auth
}

View File

@@ -12,38 +12,44 @@ import (
)
func main() {
db_user := os.Getenv("POSTGRES_USER")
db_password := os.Getenv("POSTGRES_PASSWORD")
dbname := os.Getenv("POSTGRES_DB")
db_host := os.Getenv("POSTGRES_HOST")
db_port := os.Getenv("POSTGRES_PORT")
db_config := services.SQLConfig{User: db_user, Password: db_password, DBName: dbname, Host: db_host, Port: db_port}
db, err := services.InitDatabase(db_config)
dbUser := os.Getenv("POSTGRES_USER")
dbPassword := os.Getenv("POSTGRES_PASSWORD")
dbName := os.Getenv("POSTGRES_DB")
dbHost := os.Getenv("POSTGRES_HOST")
dbPort := os.Getenv("POSTGRES_PORT")
dbConfig := services.SQLConfig{User: dbUser, Password: dbPassword, DBName: dbName, Host: dbHost, Port: dbPort}
db, err := services.InitDatabase(&dbConfig)
if err != nil {
log.Fatal(err)
}
if err != nil {
log.Fatal(err)
}
spotifyAuthState := os.Getenv("SPOTIFY_AUTH_STATE")
spotifyRedirectURL := os.Getenv("SPOTIFY_REDIRECT_URI")
spotifyClientID := os.Getenv("SPOTIFY_CLIENT_ID")
spotifyClientSecret := os.Getenv("SPOTIFY_CLIENT_SECRET")
spotifyConfig := services.SpotifyConfig{AuthState: spotifyAuthState, RedirectURL: spotifyRedirectURL, ClientID: spotifyClientID, ClientSecret: spotifyClientSecret}
spotifyAuth, client := services.InitSpotifyAuth(&spotifyConfig)
authSecret := os.Getenv("BACKEND_SECRET")
authConfig := services.AuthConfig{Secret: []byte(authSecret)}
auth := services.InitAuth(&authConfig)
store := handlers.Store{DB: db, SpotifyAuth: spotifyAuth, SpotifyClient: client, Auth: auth}
r := gin.Default()
authState := os.Getenv("SPOTIFY_AUTH_STATE")
redirectURL := os.Getenv("SPOTIFY_REDIRECT_URI")
clientID := os.Getenv("SPOTIFY_CLIENT_ID")
clientSecret := os.Getenv("SPOTIFY_CLIENT_SECRET")
spotifyConfig := services.SpotifyConfig{AuthState: authState, RedirectURL: redirectURL, ClientID: clientID, ClientSecret: clientSecret}
auth, client := services.InitSpotifyAuth(spotifyConfig)
store := handlers.Store{DB: db, SpotifyAuth: auth, SpotifyClient: client}
r.GET("/posts", store.GetPosts)
r.POST("/posts", store.CreatePost)
r.PUT("/posts/:id", store.UpdatePost)
r.GET("/callback", store.CompleteAuth)
r.GET("/user/:id", store.GetUser)
r.GET("/user", store.GetUsers)
r.POST("/user", store.CreateUser)
r.PUT("/user", store.UpdateUser)
r.POST("/refresh", store.RefreshToken)
r.GET("/callback", store.CompleteSpotifyAuth)
r.GET("/spotify", store.ListeningTo)
// r.POST("/spotify", store.SendSong)

View File

@@ -6,4 +6,5 @@ type User struct {
gorm.Model // includes ID, CreatedAt, UpdatedAt, DeletedAt
Username string `gorm:"uniqueIndex"`
Password []byte
Admin bool
}

View File

@@ -16,7 +16,7 @@ type SQLConfig struct {
Port string
}
func connectToPostgreSQL(config SQLConfig) (*gorm.DB, error) {
func connectToPostgreSQL(config *SQLConfig) (*gorm.DB, error) {
dsn := fmt.Sprintf(
"user=%s password=%s dbname=%s host=%s port=%s sslmode=disable",
config.User, config.Password, config.DBName, config.Host, config.Port,
@@ -43,7 +43,7 @@ func migrateDatabase(db *gorm.DB) error {
return nil
}
func InitDatabase(config SQLConfig) (*gorm.DB, error) {
func InitDatabase(config *SQLConfig) (*gorm.DB, error) {
db, err := connectToPostgreSQL(config)
if err != nil {
return nil, err

View File

@@ -70,7 +70,7 @@ func LoadSpotifyToken(path string) (*oauth2.Token, error) {
return tok, nil
}
func InitSpotifyAuth(config SpotifyConfig) (*spotifyauth.Authenticator, *spotify.Client) {
func InitSpotifyAuth(config *SpotifyConfig) (*spotifyauth.Authenticator, *spotify.Client) {
auth := spotifyauth.New(
spotifyauth.WithRedirectURL(config.RedirectURL),
spotifyauth.WithClientID(config.ClientID),