Refactor JWT service to include TenantID in token handling and update user service methods to accommodate multi-tenant architecture
This commit is contained in:
parent
630c2881c5
commit
44ba63410e
|
|
@ -40,7 +40,7 @@ func Authenticate(jwtService service.JWTService) gin.HandlerFunc {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
userId, err := jwtService.GetUserIDByToken(authHeader)
|
tokenInfo, err := jwtService.GetUserIDByToken(authHeader)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
response := utils.BuildResponseFailed(dto.MESSAGE_FAILED_PROSES_REQUEST, err.Error(), nil)
|
response := utils.BuildResponseFailed(dto.MESSAGE_FAILED_PROSES_REQUEST, err.Error(), nil)
|
||||||
ctx.AbortWithStatusJSON(http.StatusUnauthorized, response)
|
ctx.AbortWithStatusJSON(http.StatusUnauthorized, response)
|
||||||
|
|
@ -48,7 +48,8 @@ func Authenticate(jwtService service.JWTService) gin.HandlerFunc {
|
||||||
}
|
}
|
||||||
|
|
||||||
ctx.Set("token", authHeader)
|
ctx.Set("token", authHeader)
|
||||||
ctx.Set("user_id", userId)
|
ctx.Set("tenant_id", tokenInfo.TenantID)
|
||||||
|
ctx.Set("user_id", tokenInfo.UserID)
|
||||||
ctx.Next()
|
ctx.Next()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,16 +11,23 @@ import (
|
||||||
"github.com/golang-jwt/jwt/v4"
|
"github.com/golang-jwt/jwt/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type UserTokenInfo struct {
|
||||||
|
TenantID string `json:"tenant_id"`
|
||||||
|
UserID string `json:"user_id"`
|
||||||
|
}
|
||||||
|
|
||||||
type JWTService interface {
|
type JWTService interface {
|
||||||
GenerateAccessToken(userId string, role string) string
|
GenerateAccessToken(tenantId string, userId string, role string) string
|
||||||
GenerateRefreshToken() (string, time.Time)
|
GenerateRefreshToken() (string, time.Time)
|
||||||
ValidateToken(token string) (*jwt.Token, error)
|
ValidateToken(token string) (*jwt.Token, error)
|
||||||
GetUserIDByToken(token string) (string, error)
|
GetUserIDByToken(token string) (*UserTokenInfo, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
type jwtCustomClaim struct {
|
type jwtCustomClaim struct {
|
||||||
UserID string `json:"user_id"`
|
TenantID string `json:"tenant_id"`
|
||||||
Role string `json:"role"`
|
UserID string `json:"user_id"`
|
||||||
|
Role string `json:"role"`
|
||||||
|
|
||||||
jwt.RegisteredClaims
|
jwt.RegisteredClaims
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -48,11 +55,12 @@ func getSecretKey() string {
|
||||||
return secretKey
|
return secretKey
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *jwtService) GenerateAccessToken(userId string, role string) string {
|
func (j *jwtService) GenerateAccessToken(tenantId string, userId string, role string) string {
|
||||||
claims := jwtCustomClaim{
|
claims := jwtCustomClaim{
|
||||||
userId,
|
TenantID: tenantId,
|
||||||
role,
|
UserID: userId,
|
||||||
jwt.RegisteredClaims{
|
Role: role,
|
||||||
|
RegisteredClaims: jwt.RegisteredClaims{
|
||||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(j.accessExpiry)),
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(j.accessExpiry)),
|
||||||
Issuer: j.issuer,
|
Issuer: j.issuer,
|
||||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||||
|
|
@ -92,13 +100,17 @@ func (j *jwtService) ValidateToken(token string) (*jwt.Token, error) {
|
||||||
return jwt.Parse(token, j.parseToken)
|
return jwt.Parse(token, j.parseToken)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (j *jwtService) GetUserIDByToken(token string) (string, error) {
|
func (j *jwtService) GetUserIDByToken(token string) (*UserTokenInfo, error) {
|
||||||
tToken, err := j.ValidateToken(token)
|
tToken, err := j.ValidateToken(token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
claims := tToken.Claims.(jwt.MapClaims)
|
claims := tToken.Claims.(jwt.MapClaims)
|
||||||
id := fmt.Sprintf("%v", claims["user_id"])
|
userId := fmt.Sprintf("%v", claims["user_id"])
|
||||||
return id, nil
|
tenantId := fmt.Sprintf("%v", claims["tenant_id"])
|
||||||
|
return &UserTokenInfo{
|
||||||
|
UserID: userId,
|
||||||
|
TenantID: tenantId,
|
||||||
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -111,12 +111,13 @@ func (s *userService) Verify(ctx context.Context, req dto.UserLoginRequest) (aut
|
||||||
return authDto.TokenResponse{}, dto.ErrUserNotFound
|
return authDto.TokenResponse{}, dto.ErrUserNotFound
|
||||||
}
|
}
|
||||||
|
|
||||||
accessToken := s.jwtService.GenerateAccessToken(user.ID.String(), user.Role)
|
accessToken := s.jwtService.GenerateAccessToken(user.TenantID.String(), user.ID.String(), user.Role)
|
||||||
refreshTokenString, expiresAt := s.jwtService.GenerateRefreshToken()
|
refreshTokenString, expiresAt := s.jwtService.GenerateRefreshToken()
|
||||||
|
|
||||||
refreshToken := entities.RefreshToken{
|
refreshToken := entities.RefreshToken{
|
||||||
ID: uuid.New(),
|
ID: uuid.New(),
|
||||||
UserID: user.ID,
|
UserID: user.ID,
|
||||||
|
TenantID: user.TenantID,
|
||||||
Token: refreshTokenString,
|
Token: refreshTokenString,
|
||||||
ExpiresAt: expiresAt,
|
ExpiresAt: expiresAt,
|
||||||
}
|
}
|
||||||
|
|
@ -143,7 +144,7 @@ func (s *userService) SendVerificationEmail(ctx context.Context, req dto.SendVer
|
||||||
return dto.ErrAccountAlreadyVerified
|
return dto.ErrAccountAlreadyVerified
|
||||||
}
|
}
|
||||||
|
|
||||||
verificationToken := s.jwtService.GenerateAccessToken(user.ID.String(), "verification")
|
verificationToken := s.jwtService.GenerateAccessToken(user.TenantID.String(), user.ID.String(), "verification")
|
||||||
|
|
||||||
subject := "Email Verification"
|
subject := "Email Verification"
|
||||||
body := "Please verify your email using this token: " + verificationToken
|
body := "Please verify your email using this token: " + verificationToken
|
||||||
|
|
@ -157,12 +158,12 @@ func (s *userService) VerifyEmail(ctx context.Context, req dto.VerifyEmailReques
|
||||||
return dto.VerifyEmailResponse{}, dto.ErrTokenInvalid
|
return dto.VerifyEmailResponse{}, dto.ErrTokenInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
userId, err := s.jwtService.GetUserIDByToken(req.Token)
|
userTokenInfo, err := s.jwtService.GetUserIDByToken(req.Token)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return dto.VerifyEmailResponse{}, dto.ErrTokenInvalid
|
return dto.VerifyEmailResponse{}, dto.ErrTokenInvalid
|
||||||
}
|
}
|
||||||
|
|
||||||
user, err := s.userRepository.GetUserById(ctx, s.db, userId)
|
user, err := s.userRepository.GetUserById(ctx, s.db, userTokenInfo.UserID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return dto.VerifyEmailResponse{}, dto.ErrUserNotFound
|
return dto.VerifyEmailResponse{}, dto.ErrUserNotFound
|
||||||
}
|
}
|
||||||
|
|
@ -220,7 +221,7 @@ func (s *userService) RefreshToken(ctx context.Context, req authDto.RefreshToken
|
||||||
return authDto.TokenResponse{}, err
|
return authDto.TokenResponse{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
accessToken := s.jwtService.GenerateAccessToken(refreshToken.UserID.String(), refreshToken.User.Role)
|
accessToken := s.jwtService.GenerateAccessToken(refreshToken.TenantID.String(), refreshToken.UserID.String(), refreshToken.User.Role)
|
||||||
newRefreshTokenString, expiresAt := s.jwtService.GenerateRefreshToken()
|
newRefreshTokenString, expiresAt := s.jwtService.GenerateRefreshToken()
|
||||||
|
|
||||||
err = s.refreshTokenRepository.DeleteByToken(ctx, s.db, req.RefreshToken)
|
err = s.refreshTokenRepository.DeleteByToken(ctx, s.db, req.RefreshToken)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue