generated from Ayobami6/go_starter
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added JWT-based authentication, including login and registration functionalities. A `GetUserByEmail` repository method was implemented to support login. The user model now initializes with a default wallet balance of 0. Updated dependencies to include JWT support and refreshed related packages.
- Loading branch information
Showing
13 changed files
with
208 additions
and
10 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,9 +1,18 @@ | ||
package model | ||
|
||
type User struct { | ||
Id string `bson:"_id,omitempty" json:"id"` | ||
Name string `bson:"name" json:"name"` | ||
Email string `bson:"email" json:"email"` | ||
Password string `bson:"password" json:"password"` | ||
WalletBalance string `bson:"wallet_balance" json:"wallet_balance"` | ||
Id string `bson:"_id,omitempty" json:"id"` | ||
Name string `bson:"name" json:"name"` | ||
Email string `bson:"email" json:"email"` | ||
Password string `bson:"password" json:"password"` | ||
WalletBalance float64 `bson:"wallet_balance" json:"wallet_balance"` | ||
} | ||
|
||
func NewUser(name string, email string, password string) *User { | ||
return &User{ | ||
Name: name, | ||
Email: email, | ||
Password: password, | ||
WalletBalance: 0.0, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package dto | ||
|
||
type CreateUserDTO struct { | ||
Name string `json:"name" binding:"required"` | ||
Email string `json:"email" binding:"required"` | ||
Password string `json:"password" binding:"required"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
package dto | ||
|
||
type LoginDTO struct { | ||
Email string `json:"username" binding:"required"` | ||
Password string `json:"password" binding:"required"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
package dto | ||
|
||
type LoginResponseDTO struct { | ||
AccessToken string `json:"accessToken"` | ||
ExpiresIn string `json:"expiresIn"` | ||
TokenType string `json:"tokenType"` | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,92 @@ | ||
package impls | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"log" | ||
"strconv" | ||
"time" | ||
|
||
"github.com/LoginX/SprayDash/config" | ||
"github.com/LoginX/SprayDash/internal/model" | ||
"github.com/LoginX/SprayDash/internal/repository" | ||
"github.com/LoginX/SprayDash/internal/service/dto" | ||
"github.com/LoginX/SprayDash/pkg/auth" | ||
) | ||
|
||
type UserServiceImpl struct { | ||
// depends on | ||
repo repository.UserRepository | ||
} | ||
|
||
func NewUserServiceImpl(repo repository.UserRepository) *UserServiceImpl { | ||
return &UserServiceImpl{ | ||
repo: repo, | ||
} | ||
} | ||
|
||
// implement interface methods | ||
|
||
func (s *UserServiceImpl) Register(createUserDto dto.CreateUserDTO) (string, error) { | ||
// need to hash the password | ||
hashedPassword, hashErr := auth.HashPassword(createUserDto.Password) | ||
if hashErr != nil { | ||
return "", hashErr | ||
} | ||
// check if user already exists | ||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) | ||
defer cancel() | ||
_, existErr := s.repo.GetUserByEmail(ctx, createUserDto.Email) | ||
if existErr == nil { | ||
return "", errors.New("user already exists") | ||
} | ||
|
||
newUser := model.NewUser(createUserDto.Name, createUserDto.Email, hashedPassword) | ||
|
||
// Call the CreateUser function with the context | ||
_, err := s.repo.CreateUser(ctx, newUser) | ||
if err != nil { | ||
if errors.Is(err, context.DeadlineExceeded) { | ||
return "", errors.New("request timed out") | ||
} | ||
return "", err | ||
} | ||
return "User registered successfully", nil | ||
|
||
} | ||
|
||
func (s *UserServiceImpl) Login(loginDto dto.LoginDTO) (dto.LoginResponseDTO, error) { | ||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second) | ||
defer cancel() | ||
// get user by the email | ||
user, err := s.repo.GetUserByEmail(ctx, loginDto.Email) | ||
if err != nil { | ||
if errors.Is(err, context.DeadlineExceeded) { | ||
return dto.LoginResponseDTO{}, errors.New("request timed out") | ||
} | ||
return dto.LoginResponseDTO{}, err | ||
} | ||
// compare password | ||
if !auth.ComparePassword(user.Password, loginDto.Password) { | ||
return dto.LoginResponseDTO{}, errors.New("invalid credentials") | ||
} | ||
|
||
secret := []byte(config.GetEnv("JWT_SECRET", "somesecret")) | ||
exp, expErr := strconv.Atoi(config.GetEnv("JWT_EXP", "3600")) | ||
if expErr != nil { | ||
log.Println("Error converting JWT_EXP to int: ", expErr) | ||
return dto.LoginResponseDTO{}, expErr | ||
} | ||
token, tokenErr := auth.CreateJWT(secret, exp, user) | ||
if tokenErr != nil { | ||
log.Println("Error creating JWT: ", tokenErr) | ||
return dto.LoginResponseDTO{}, errors.New("error creating a token") | ||
} | ||
// return token | ||
return dto.LoginResponseDTO{ | ||
AccessToken: token["token"], | ||
ExpiresIn: token["expiresAt"], | ||
TokenType: "jwt", | ||
}, nil | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,9 @@ | ||
package service | ||
|
||
import "github.com/LoginX/SprayDash/internal/service/dto" | ||
|
||
// user service interface | ||
type UserService interface { | ||
Login(loginDto dto.LoginDTO) (string, error) | ||
Register(createUserDto dto.CreateUserDTO) (dto.LoginResponseDTO, error) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1 +1,30 @@ | ||
package auth | ||
|
||
import ( | ||
"time" | ||
|
||
"github.com/LoginX/SprayDash/internal/model" | ||
"github.com/golang-jwt/jwt/v5" | ||
) | ||
|
||
type contextKey string | ||
|
||
var UserKey contextKey = "user" | ||
|
||
func CreateJWT(secret []byte, expiration int, user *model.User) (map[string]string, error) { | ||
expAt := time.Now().Add(time.Duration(expiration) * time.Minute).Unix() | ||
// create te token claim | ||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwt.MapClaims{ | ||
"user": user, | ||
"exp": expAt, | ||
}) | ||
tokenString, err := token.SignedString(secret) | ||
if err != nil { | ||
return nil, err | ||
} | ||
data := map[string]string{ | ||
"token": tokenString, | ||
"expiresAt": time.Unix(expAt, 0).String(), | ||
} | ||
return data, nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
package auth | ||
|
||
import ( | ||
"golang.org/x/crypto/bcrypt" | ||
) | ||
|
||
func HashPassword(password string) (string, error) { | ||
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost) | ||
if err != nil { | ||
return "", err | ||
} | ||
return string(hash), nil | ||
} | ||
|
||
func ComparePassword(hashedPassword string, password string) bool { | ||
err := bcrypt.CompareHashAndPassword([]byte(hashedPassword), []byte(password)) | ||
return err == nil | ||
} |
Binary file not shown.