adding jwt tokens
This commit is contained in:
@@ -4,7 +4,9 @@ go 1.24.0
|
|||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/gin-gonic/gin v1.11.0
|
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
|
github.com/zmb3/spotify/v2 v2.4.3
|
||||||
|
golang.org/x/crypto v0.43.0
|
||||||
golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5
|
golang.org/x/oauth2 v0.0.0-20210810183815-faf39c7919d5
|
||||||
gorm.io/driver/postgres v1.6.0
|
gorm.io/driver/postgres v1.6.0
|
||||||
gorm.io/gorm v1.31.1
|
gorm.io/gorm v1.31.1
|
||||||
@@ -41,7 +43,6 @@ require (
|
|||||||
github.com/ugorji/go/codec v1.3.0 // indirect
|
github.com/ugorji/go/codec v1.3.0 // indirect
|
||||||
go.uber.org/mock v0.5.0 // indirect
|
go.uber.org/mock v0.5.0 // indirect
|
||||||
golang.org/x/arch v0.20.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/mod v0.29.0 // indirect
|
||||||
golang.org/x/net v0.46.0 // indirect
|
golang.org/x/net v0.46.0 // indirect
|
||||||
golang.org/x/sync v0.17.0 // indirect
|
golang.org/x/sync v0.17.0 // indirect
|
||||||
|
|||||||
@@ -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-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 h1:8W7wMFS12Pcas7KU+VVkaiCng+kG8QiFeFwzFb+rwuw=
|
||||||
github.com/goccy/go-yaml v1.18.0/go.mod h1:XBurs7gK8ATbW4ZPGKgcbrY1Br56PdM69F7LkFRi1kA=
|
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/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-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
|
|||||||
@@ -1 +1,75 @@
|
|||||||
package handlers
|
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) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package handlers
|
package handlers
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"adam-french.co.uk/backend/services"
|
||||||
"github.com/zmb3/spotify/v2"
|
"github.com/zmb3/spotify/v2"
|
||||||
spotifyauth "github.com/zmb3/spotify/v2/auth"
|
spotifyauth "github.com/zmb3/spotify/v2/auth"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
@@ -10,4 +11,5 @@ type Store struct {
|
|||||||
DB *gorm.DB
|
DB *gorm.DB
|
||||||
SpotifyAuth *spotifyauth.Authenticator
|
SpotifyAuth *spotifyauth.Authenticator
|
||||||
SpotifyClient *spotify.Client
|
SpotifyClient *spotify.Client
|
||||||
|
Auth *services.Auth
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -12,38 +12,44 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
db_user := os.Getenv("POSTGRES_USER")
|
dbUser := os.Getenv("POSTGRES_USER")
|
||||||
db_password := os.Getenv("POSTGRES_PASSWORD")
|
dbPassword := os.Getenv("POSTGRES_PASSWORD")
|
||||||
dbname := os.Getenv("POSTGRES_DB")
|
dbName := os.Getenv("POSTGRES_DB")
|
||||||
db_host := os.Getenv("POSTGRES_HOST")
|
dbHost := os.Getenv("POSTGRES_HOST")
|
||||||
db_port := os.Getenv("POSTGRES_PORT")
|
dbPort := os.Getenv("POSTGRES_PORT")
|
||||||
db_config := services.SQLConfig{User: db_user, Password: db_password, DBName: dbname, Host: db_host, Port: db_port}
|
dbConfig := services.SQLConfig{User: dbUser, Password: dbPassword, DBName: dbName, Host: dbHost, Port: dbPort}
|
||||||
db, err := services.InitDatabase(db_config)
|
db, err := services.InitDatabase(&dbConfig)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err != nil {
|
spotifyAuthState := os.Getenv("SPOTIFY_AUTH_STATE")
|
||||||
log.Fatal(err)
|
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()
|
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.GET("/posts", store.GetPosts)
|
||||||
r.POST("/posts", store.CreatePost)
|
r.POST("/posts", store.CreatePost)
|
||||||
r.PUT("/posts/:id", store.UpdatePost)
|
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.GET("/spotify", store.ListeningTo)
|
||||||
// r.POST("/spotify", store.SendSong)
|
// r.POST("/spotify", store.SendSong)
|
||||||
|
|
||||||
|
|||||||
@@ -6,4 +6,5 @@ type User struct {
|
|||||||
gorm.Model // includes ID, CreatedAt, UpdatedAt, DeletedAt
|
gorm.Model // includes ID, CreatedAt, UpdatedAt, DeletedAt
|
||||||
Username string `gorm:"uniqueIndex"`
|
Username string `gorm:"uniqueIndex"`
|
||||||
Password []byte
|
Password []byte
|
||||||
|
Admin bool
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ type SQLConfig struct {
|
|||||||
Port string
|
Port string
|
||||||
}
|
}
|
||||||
|
|
||||||
func connectToPostgreSQL(config SQLConfig) (*gorm.DB, error) {
|
func connectToPostgreSQL(config *SQLConfig) (*gorm.DB, error) {
|
||||||
dsn := fmt.Sprintf(
|
dsn := fmt.Sprintf(
|
||||||
"user=%s password=%s dbname=%s host=%s port=%s sslmode=disable",
|
"user=%s password=%s dbname=%s host=%s port=%s sslmode=disable",
|
||||||
config.User, config.Password, config.DBName, config.Host, config.Port,
|
config.User, config.Password, config.DBName, config.Host, config.Port,
|
||||||
@@ -43,7 +43,7 @@ func migrateDatabase(db *gorm.DB) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitDatabase(config SQLConfig) (*gorm.DB, error) {
|
func InitDatabase(config *SQLConfig) (*gorm.DB, error) {
|
||||||
db, err := connectToPostgreSQL(config)
|
db, err := connectToPostgreSQL(config)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ func LoadSpotifyToken(path string) (*oauth2.Token, error) {
|
|||||||
return tok, nil
|
return tok, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func InitSpotifyAuth(config SpotifyConfig) (*spotifyauth.Authenticator, *spotify.Client) {
|
func InitSpotifyAuth(config *SpotifyConfig) (*spotifyauth.Authenticator, *spotify.Client) {
|
||||||
auth := spotifyauth.New(
|
auth := spotifyauth.New(
|
||||||
spotifyauth.WithRedirectURL(config.RedirectURL),
|
spotifyauth.WithRedirectURL(config.RedirectURL),
|
||||||
spotifyauth.WithClientID(config.ClientID),
|
spotifyauth.WithClientID(config.ClientID),
|
||||||
|
|||||||
Reference in New Issue
Block a user