From 11bc12b1f12ed794f0a53a3b0d539a16dc8bd04a Mon Sep 17 00:00:00 2001 From: Vidhu Kant Sharma Date: Tue, 29 Nov 2022 19:04:16 +0530 Subject: added basic login system with password authentication --- auth/auth.go | 48 +++++++++++++++++++++++++++++++++++++----------- user/db_actions.go | 5 ++++- user/router.go | 50 +++++++++++++++++++++----------------------------- 3 files changed, 62 insertions(+), 41 deletions(-) diff --git a/auth/auth.go b/auth/auth.go index ae20d23..7d88787 100644 --- a/auth/auth.go +++ b/auth/auth.go @@ -20,13 +20,13 @@ package auth import ( "github.com/gin-gonic/gin" "context" - "fmt" "go.mongodb.org/mongo-driver/bson" "go.mongodb.org/mongo-driver/mongo" "github.com/MikunoNaka/OpenBills-server/database" "github.com/MikunoNaka/OpenBills-server/user" "net/http" - //"golang.org/x/crypto/bcrypt" + "log" + "golang.org/x/crypto/bcrypt" ) var db *mongo.Collection = database.DB.Collection("Users") @@ -37,24 +37,50 @@ func checkPassword() gin.HandlerFunc { ctx.BindJSON(&u) filter := bson.M{ - "UserName": u.UserName, - "$or": bson.M{"Email": u.Email}, + "$or": []bson.M{ + // u.UserName in this case can be either username or email + {"Email": u.UserName}, + {"UserName": u.UserName}, + }, } - err := db.FindOne(context.TODO(), filter).Decode(&u) + // check if the user exists in DB + var user user.User + err := db.FindOne(context.TODO(), filter).Decode(&user) if err != nil { - panic(err) + if err == mongo.ErrNoDocuments { + ctx.JSON(http.StatusNotFound, gin.H{"error": "user does not exist"}) + } else { + log.Printf("Error while reading user from DB to check password: %v", err.Error()) + ctx.JSON(http.StatusInternalServerError, gin.H{"error": "internal server error"}) + } + ctx.Abort() } - fmt.Println(u) + + // compare hash and password + err = bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(u.Password)) + if err != nil { + if err == bcrypt.ErrMismatchedHashAndPassword { + ctx.JSON(http.StatusUnauthorized, gin.H{"error": "incorrect password"}) + } else { + log.Printf("Error while checking password: %v", err.Error()) + ctx.JSON(http.StatusInternalServerError, gin.H{"error": "internal server error"}) + } + ctx.Abort() + } + + // everything's fine! + ctx.Set("user", user) + ctx.Next() } } func Routes(route *gin.Engine) { - u := route.Group("/auth") + r := route.Group("/auth") { - u.POST("/login", func(ctx *gin.Context) { - checkPassword()(ctx) - ctx.HTML(http.StatusOK, "

Hello World

", nil) + r.POST("/login", checkPassword(), func(ctx *gin.Context) { + user := ctx.MustGet("user").(user.User) + ctx.JSON(http.StatusOK, user) }) } } diff --git a/user/db_actions.go b/user/db_actions.go index 611507d..2d89b7e 100644 --- a/user/db_actions.go +++ b/user/db_actions.go @@ -26,7 +26,10 @@ import ( // Add user to db func saveUser(u User) (primitive.ObjectID, error) { - u.hashPassword() + err := u.hashPassword() + if err != nil { + return *new(primitive.ObjectID), err + } res, err := db.InsertOne(context.TODO(), u) return res.InsertedID.(primitive.ObjectID), err } diff --git a/user/router.go b/user/router.go index ab1dff8..15d6efb 100644 --- a/user/router.go +++ b/user/router.go @@ -20,7 +20,6 @@ package user import ( "github.com/gin-gonic/gin" "go.mongodb.org/mongo-driver/bson/primitive" - "golang.org/x/crypto/bcrypt" "log" "net/http" ) @@ -31,16 +30,9 @@ func Routes(route *gin.Engine) { { u.POST("/new", validateMiddleware(), func(ctx *gin.Context) { u := ctx.MustGet("user").(User) - // hash password - pass := []byte(u.Password) - hash, err := bcrypt.GenerateFromPassword(pass, bcrypt.DefaultCost) - if err != nil { - ctx.JSON(http.StatusInternalServerError, gin.H{"error": "could not login"}) - log.Printf("ERROR: Failed to hash password: %v\n", err.Error()) - } - u.Password = string(hash) + // TODO: maybe add an invite code for some instances - _, err = saveUser(u) + _, err := saveUser(u) if err != nil { ctx.JSON(http.StatusInternalServerError, gin.H{"error": "could not login"}) log.Printf("ERROR: Failed to add new user %v to DB: %v\n", u, err.Error()) @@ -51,27 +43,27 @@ func Routes(route *gin.Engine) { ctx.JSON(http.StatusOK, nil) }) - u.PUT("/:userId", func(ctx *gin.Context) { - id := ctx.Param("userId") - objectId, err := primitive.ObjectIDFromHex(id) - if err != nil { - ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) - log.Printf("ERROR: Failed to modify user, Error parsing ID: %v\n", err.Error()) - return - } + u.PUT("/:userId", func(ctx *gin.Context) { + id := ctx.Param("userId") + objectId, err := primitive.ObjectIDFromHex(id) + if err != nil { + ctx.JSON(http.StatusBadRequest, gin.H{"error": err.Error()}) + log.Printf("ERROR: Failed to modify user, Error parsing ID: %v\n", err.Error()) + return + } - var u User - ctx.BindJSON(&u) - err = modifyUser(objectId, u) - if err != nil { - ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) - log.Printf("ERROR: Failed to modify user %v: %v\n", objectId, err.Error()) - return - } + var u User + ctx.BindJSON(&u) + err = modifyUser(objectId, u) + if err != nil { + ctx.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()}) + log.Printf("ERROR: Failed to modify user %v: %v\n", objectId, err.Error()) + return + } - log.Printf("Modified user %v to %v.\n", objectId, u) - ctx.JSON(http.StatusOK, nil) - }) + log.Printf("Modified user %v to %v.\n", objectId, u) + ctx.JSON(http.StatusOK, nil) + }) u.DELETE("/:userId", func(ctx *gin.Context) { id := ctx.Param("userId") -- cgit v1.2.3