fix: get profile user/staff using token rather than id

This commit is contained in:
ericprd 2025-02-28 12:18:47 +08:00
parent 5fb0764630
commit 6b858b99fb
15 changed files with 234 additions and 44 deletions

View File

@ -1,9 +1,5 @@
package config
import (
"legalgo-BE-go/internal/utilities/utils"
)
var (
APP_PORT int
GRACEFULL_TIMEOUT int
@ -13,16 +9,19 @@ var (
DB_USER,
DB_PASSWORD,
DB_NAME,
DB_PORT string
DB_PORT,
SALT_SECURITY string
)
func InitEnv() {
DB_HOST = utils.GetOrDefault("DB_HOST", "localhost")
DB_USER = utils.GetOrDefault("DB_USER", "")
DB_PASSWORD = utils.GetOrDefault("DB_PASSWORD", "")
DB_NAME = utils.GetOrDefault("DB_NAME", "")
DB_PORT = utils.GetOrDefault("DB_PORT", "")
DB_HOST = GetOrDefault("DB_HOST", "localhost")
DB_USER = GetOrDefault("DB_USER", "")
DB_PASSWORD = GetOrDefault("DB_PASSWORD", "")
DB_NAME = GetOrDefault("DB_NAME", "")
DB_PORT = GetOrDefault("DB_PORT", "")
APP_PORT = utils.GetOrDefault("APP_PORT", 3000)
GRACEFULL_TIMEOUT = utils.GetOrDefault("GRACEFULL_TIMEOUT", 10)
SALT_SECURITY = GetOrDefault("SALT_SECURITY", "legalgo")
APP_PORT = GetOrDefault("APP_PORT", 3000)
GRACEFULL_TIMEOUT = GetOrDefault("GRACEFULL_TIMEOUT", 10)
}

View File

@ -1,4 +1,4 @@
package utils
package config
import (
"os"

View File

@ -0,0 +1,29 @@
package userrepository
import (
"errors"
authdomain "legalgo-BE-go/internal/domain/auth"
"gorm.io/gorm"
)
func (ur *UserRepository) GetUserProfile(email string) (*authdomain.UserProfile, error) {
var users []authdomain.UserProfile
if email == "" {
return nil, errors.New("email is empty")
}
if err := ur.DB.Table("users u").
Select("u.email, u.id, s.status as subscribe_status, sp.code as subscribe_plan_code, sp.name as subscribe_plan_name").
Joins("join subscribes s on s.id = u.subscribe_id").
Joins("join subscribe_plans sp on s.subscribe_plan_id = sp.id").
Scan(&users).Error; err != nil {
if errors.Is(err, gorm.ErrRecordNotFound) {
return nil, errors.New("user not found")
}
return nil, err
}
return &users[0], nil
}

View File

@ -12,6 +12,7 @@ type UserRepository struct {
type UserIntf interface {
GetUserByEmail(string) (*authdomain.User, error)
GetUserByID(string) (*authdomain.UserProfile, error)
GetUserProfile(string) (*authdomain.UserProfile, error)
CreateUser(*authdomain.User) (*authdomain.User, error)
}

View File

@ -4,7 +4,9 @@ import (
"errors"
authsvc "legalgo-BE-go/internal/services/auth"
"legalgo-BE-go/internal/utilities/response"
"legalgo-BE-go/internal/utilities/utils"
"net/http"
"strings"
"github.com/go-chi/chi/v5"
)
@ -13,14 +15,15 @@ func GetStaffProfile(
router chi.Router,
authSvc authsvc.AuthIntf,
) {
router.Get("/staff/{id}/profile", func(w http.ResponseWriter, r *http.Request) {
router.Get("/staff/profile", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
id := chi.URLParam(r, "id")
if id == "" {
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
response.ResponseWithErrorCode(
ctx,
w,
errors.New("provided id is empty"),
errors.New("provided auth is empty"),
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"required params is not provided",
@ -28,7 +31,45 @@ func GetStaffProfile(
return
}
staffProfile, err := authSvc.GetStaffProfile(id)
if !strings.HasPrefix(authHeader, "Bearer") {
response.ResponseWithErrorCode(
ctx,
w,
errors.New("invalid authorization token"),
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"invalid required token",
)
return
}
token := strings.Split(authHeader, " ")
if len(token) < 2 {
response.ResponseWithErrorCode(
ctx,
w,
errors.New("invalid authorization"),
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"invalid required token",
)
return
}
destructedToken, err := utils.DestructToken(token[1])
if err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
staffProfile, err := authSvc.GetStaffProfile(destructedToken.Email)
if err != nil {
response.ResponseWithErrorCode(
ctx,
@ -49,14 +90,15 @@ func GetUserProfile(
router chi.Router,
authSvc authsvc.AuthIntf,
) {
router.Get("/user/{id}/profile", func(w http.ResponseWriter, r *http.Request) {
router.Get("/user/profile", func(w http.ResponseWriter, r *http.Request) {
ctx := r.Context()
id := chi.URLParam(r, "id")
if id == "" {
authHeader := r.Header.Get("Authorization")
if authHeader == "" {
response.ResponseWithErrorCode(
ctx,
w,
errors.New("provided id is empty"),
errors.New("provided auth is empty"),
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"required params is not provided",
@ -64,7 +106,45 @@ func GetUserProfile(
return
}
userProfile, err := authSvc.GetUserProfile(id)
if !strings.HasPrefix(authHeader, "Bearer") {
response.ResponseWithErrorCode(
ctx,
w,
errors.New("invalid authorization token"),
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"invalid required token",
)
return
}
token := strings.Split(authHeader, " ")
if len(token) < 2 {
response.ResponseWithErrorCode(
ctx,
w,
errors.New("invalid authorization"),
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
"invalid required token",
)
return
}
destructedToken, err := utils.DestructToken(token[1])
if err != nil {
response.ResponseWithErrorCode(
ctx,
w,
err,
response.ErrBadRequest.Code,
response.ErrBadRequest.HttpCode,
err.Error(),
)
return
}
userProfile, err := authSvc.GetUserProfile(destructedToken.Email)
if err != nil {
response.ResponseWithErrorCode(
ctx,

View File

@ -0,0 +1,6 @@
package authdomain
type AuthToken struct {
Email string
SessionID string
}

View File

@ -4,7 +4,7 @@ type JWTClaim string
const (
TYPE JWTClaim = "type"
USERNAME JWTClaim = "username"
EMAIL JWTClaim = "email"
EXPIRED_AT JWTClaim = "exp"
SESSION_ID JWTClaim = "sid"
ISSUED_AT JWTClaim = "iat"

View File

@ -2,8 +2,8 @@ package authsvc
import authdomain "legalgo-BE-go/internal/domain/auth"
func (as *AuthSvc) GetStaffProfile(id string) (*authdomain.StaffProfile, error) {
staff, err := as.staffRepo.GetStaffByID(id)
func (as *AuthSvc) GetStaffProfile(email string) (*authdomain.StaffProfile, error) {
staff, err := as.staffRepo.GetStaffByEmail(email)
if err != nil {
return nil, err
}

View File

@ -2,8 +2,8 @@ package authsvc
import authdomain "legalgo-BE-go/internal/domain/auth"
func (as *AuthSvc) GetUserProfile(id string) (*authdomain.UserProfile, error) {
user, err := as.userRepo.GetUserByID(id)
func (as *AuthSvc) GetUserProfile(email string) (*authdomain.UserProfile, error) {
user, err := as.userRepo.GetUserProfile(email)
if err != nil {
return nil, err
}

View File

@ -5,6 +5,8 @@ import (
authdomain "legalgo-BE-go/internal/domain/auth"
"legalgo-BE-go/internal/utilities/utils"
"github.com/google/uuid"
)
func (sv *AuthSvc) LoginAsStaff(spec authdomain.LoginReq) (string, error) {
@ -18,7 +20,12 @@ func (sv *AuthSvc) LoginAsStaff(spec authdomain.LoginReq) (string, error) {
return "", errors.New("wrong password")
}
token, err := utils.GenerateToken(staff.Email)
authToken := authdomain.AuthToken{
Email: staff.Email,
SessionID: uuid.NewString(),
}
token, err := utils.GenerateToken(authToken)
if err != nil {
return "", errors.New(err.Error())
}

View File

@ -5,6 +5,8 @@ import (
authdomain "legalgo-BE-go/internal/domain/auth"
"legalgo-BE-go/internal/utilities/utils"
"github.com/google/uuid"
)
func (a *AuthSvc) LoginAsUser(spec authdomain.LoginReq) (string, error) {
@ -18,7 +20,12 @@ func (a *AuthSvc) LoginAsUser(spec authdomain.LoginReq) (string, error) {
return "", errors.New("wrong password")
}
token, err := utils.GenerateToken(user.Email)
authToken := authdomain.AuthToken{
Email: user.Email,
SessionID: uuid.NewString(),
}
token, err := utils.GenerateToken(authToken)
if err != nil {
return "", errors.New(err.Error())
}

View File

@ -19,19 +19,24 @@ func (a *AuthSvc) RegisterStaff(spec authdomain.RegisterStaffReq) (string, error
return "", err
}
user := authdomain.Staff{
staff := authdomain.Staff{
ID: uuid.NewString(),
Email: spec.Email,
Password: hashedPwd,
Username: spec.Username,
}
_, err = a.staffRepo.Create(&user)
_, err = a.staffRepo.Create(&staff)
if err != nil {
return "", errors.New(err.Error())
}
token, err := utils.GenerateToken(spec.Email)
authToken := authdomain.AuthToken{
Email: staff.Email,
SessionID: uuid.NewString(),
}
token, err := utils.GenerateToken(authToken)
if err != nil {
return "", errors.New(err.Error())
}

View File

@ -48,7 +48,12 @@ func (a *AuthSvc) RegisterUser(spec authdomain.RegisterUserReq) (string, error)
return "", errors.New(err.Error())
}
token, err := utils.GenerateToken(spec.Email)
authToken := authdomain.AuthToken{
Email: user.Email,
SessionID: uuid.NewString(),
}
token, err := utils.GenerateToken(authToken)
if err != nil {
return "", errors.New(err.Error())
}

View File

@ -1,15 +1,18 @@
package utils
import (
"errors"
"fmt"
"time"
"legalgo-BE-go/config"
authdomain "legalgo-BE-go/internal/domain/auth"
jwtclaimenum "legalgo-BE-go/internal/enums/jwt"
timeutils "legalgo-BE-go/internal/utilities/time_utils"
"github.com/golang-jwt/jwt/v5"
)
var jwtSecret = []byte("secret jwt key") // TODO: change later from env
type ClaimOption func(options jwt.MapClaims)
// func GenerateToken(options ...ClaimOption) (string, error) {
@ -28,12 +31,60 @@ type ClaimOption func(options jwt.MapClaims)
// return token.SignedString(jwtSecret)
// }
func GenerateToken(email string) (string, error) {
func GenerateToken(data authdomain.AuthToken) (string, error) {
now := timeutils.Now()
token := jwt.New(jwt.SigningMethodHS256)
claims := token.Claims.(jwt.MapClaims)
claims["email"] = email
claims["exp"] = now.Add(time.Hour).Unix()
return token.SignedString(jwtSecret)
claims := jwt.MapClaims{
"email": data.Email,
"session_id": data.SessionID,
"exp": now.Add(1 * time.Hour).Unix(),
}
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
return token.SignedString([]byte(config.SALT_SECURITY))
}
func parseToken(s string) (*jwt.Token, error) {
return jwt.Parse(s, func(t *jwt.Token) (any, error) {
if _, ok := t.Method.(*jwt.SigningMethodHMAC); !ok {
errMsg := fmt.Sprintf("unexpected signing method: %v", t.Header["alg"])
return nil, errors.New(errMsg)
}
return []byte(config.SALT_SECURITY), nil
})
}
func DestructToken(s string) (authdomain.AuthToken, error) {
var data authdomain.AuthToken
token, err := parseToken(s)
if err != nil {
return data, err
}
claims, ok := token.Claims.(jwt.MapClaims)
if !ok {
return data, errors.New("failed to parse token")
}
if !token.Valid {
return data, errors.New("invalid token")
}
email, ok := claims[string(jwtclaimenum.EMAIL)].(string)
if !ok {
return data, errors.New("invalid email")
}
sessionId, ok := claims[string(jwtclaimenum.SESSION_ID)].(string)
data = authdomain.AuthToken{
Email: email,
SessionID: sessionId,
}
return data, nil
}

View File

@ -120,7 +120,7 @@ paths:
message:
type: string
/staff/{id}/profile:
/staff/profile:
get:
summary: "get staff profile"
tags:
@ -164,7 +164,7 @@ paths:
message:
type: string
/user/{id}/profile:
/user/profile:
get:
summary: "get staff profile"
tags: