Skip to content

Commit

Permalink
add jwt package, generate token
Browse files Browse the repository at this point in the history
  • Loading branch information
alireza-fa committed Feb 17, 2024
1 parent e599968 commit 4d909a4
Show file tree
Hide file tree
Showing 8 changed files with 145 additions and 2 deletions.
5 changes: 5 additions & 0 deletions .env
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,8 @@ SEQ_API_KEY=n1VeAtQ3lbzdmE8BfWFx
BASE_URL=localhost

NOTIFICATION_SERVICE=dummy

ACCESS_TOKEN_LIFETIME_IN_MINUTES=10
REFRESH_TOKEN_LIFETIME_IN_DAYS=1
ACCESS_TOKEN_SECRET_KEY='$@pj!0=+cztp@7*#d@74uloh2#s&ghtpup1@sb6k809rv+n%@k'
REFRESH_TOKEN_SECRET_KEY='$@pj!0=+cztp@9*#d@53uloh2#s&ghtpup1@sb5k809rv+n%@k'
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ require (
github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.18.0 // indirect
github.com/go-redis/redis v6.15.9+incompatible // indirect
github.com/golang-jwt/jwt/v5 v5.2.0 // indirect
github.com/jackc/pgpassfile v1.0.0 // indirect
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 // indirect
github.com/jackc/pgx/v5 v5.5.3 // indirect
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ github.com/go-playground/validator/v10 v10.18.0 h1:BvolUXjp4zuvkZ5YN5t7ebzbhlUtP
github.com/go-playground/validator/v10 v10.18.0/go.mod h1:dbuPbCMFw/DrkbEynArYaCwl3amGuJotoKCe95atGMM=
github.com/go-redis/redis v6.15.9+incompatible h1:K0pv1D7EQUjfyoMql+r/jZqCLizCGKFlFgcHWWmHQjg=
github.com/go-redis/redis v6.15.9+incompatible/go.mod h1:NAIEuMOZ/fxfXJIrKDQDz8wamY7mA7PouImQ2Jvg6kA=
github.com/golang-jwt/jwt/v5 v5.2.0 h1:d/ix8ftRUorsN+5eMIlF4T6J8CAt9rch3My2winC1Jw=
github.com/golang-jwt/jwt/v5 v5.2.0/go.mod h1:pqrtFR0X4osieyHYxtmOUWsAWrfe1Q5UVIyoH402zdk=
github.com/jackc/pgpassfile v1.0.0 h1:/6Hmqy13Ss2zCq62VdNG8tM1wchn8zjSGOBJ6icpsIM=
github.com/jackc/pgpassfile v1.0.0/go.mod h1:CEx0iS5ambNFdcRtxPj5JhEz+xB6uRky5eyVu/W2HEg=
github.com/jackc/pgservicefile v0.0.0-20231201235250-de7065d80cb9 h1:L0QtFUgDarD7Fpv9jeVMgy/+Ec0mtnmYuImjTz6dtDA=
Expand Down
7 changes: 7 additions & 0 deletions src/api/dto/user.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,10 @@ type UserLogin struct {
UserName string `json:"userName" validate:"required,max=64,min=5"`
Password string `json:"password" validate:"required,min=8,max=64,containsany=abcdefghijklmnopqrstuvwxyz,containsany=ABCDEFGHIJKLMNOPQRSTUVWXYZ,containsany=1234567890"`
}

type TokenDetail struct {
AccessToken string `json:"accessToken"`
RefreshToken string `json:"refreshToken"`
AccessTokenExpireTime int64 `json:"accessTokenExpireTime"`
RefreshTokenExpireTime int64 `json:"refreshTokenExpireTime"`
}
6 changes: 6 additions & 0 deletions src/constants/token.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package constants

const (
AccessTokenLifetime = "ACCESS_TOKEN_LIFETIME_IN_MINUTES"
RefreshTokenLifetime = "REFRESH_TOKEN_LIFETIME_IN_DAYS"
)
16 changes: 16 additions & 0 deletions src/constants/user.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package constants

const (
AdminRole string = "admin"
DefaultRole string = "default"

AuthorizationHeaderKey string = "Authorization"
UserIdKey string = "UserId"
UserNameKey string = "UserName"
FullNameKey string = "FullName"
EmailKey string = "Email"
RolesKey string = "Roles"
ExpireTimeKey string = "ExpireTime"
AccessTokenSecretKey string = "ACCESS_TOKEN_SECRET_KEY"
RefreshTokenSecretKey string = "REFRESH_TOKEN_SECRET_KEY"
)
69 changes: 69 additions & 0 deletions src/services/token_service.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
package services

import (
"github.com/alireza-fa/blog-go/src/api/dto"
"github.com/alireza-fa/blog-go/src/constants"
"github.com/alireza-fa/blog-go/src/pkg/logging"
"github.com/golang-jwt/jwt/v5"
"os"
"strconv"
"time"
)

type TokenService struct {
logger logging.Logger
}

type TokenDto struct {
UserId int
FullName string
UserName string
Email string
Roles []string
}

func NewTokenService() *TokenService {
return &TokenService{
logger: logging.NewLogger(),
}
}

func (s *TokenService) GenerateToken(token *TokenDto) (*dto.TokenDetail, error) {
td := &dto.TokenDetail{}

accessTokenDuration, _ := strconv.Atoi(os.Getenv(constants.AccessTokenLifetime))
td.AccessTokenExpireTime = time.Now().Add(time.Duration(accessTokenDuration) * time.Minute).Unix()

refreshTokenDuration, _ := strconv.Atoi(os.Getenv(constants.RefreshTokenLifetime))
td.RefreshTokenExpireTime = time.Now().Add(time.Duration(refreshTokenDuration) * time.Hour * 24).Unix()

act := jwt.MapClaims{}

act[constants.UserIdKey] = token.UserId
act[constants.FullNameKey] = token.FullName
act[constants.UserNameKey] = token.UserName
act[constants.EmailKey] = token.Email
act[constants.RolesKey] = token.Roles
act[constants.ExpireTimeKey] = td.AccessTokenExpireTime
ac := jwt.NewWithClaims(jwt.SigningMethodHS256, act)

var err error
td.AccessToken, err = ac.SignedString([]byte(os.Getenv(constants.AccessTokenSecretKey)))
if err != nil {
return nil, err
}

rtc := jwt.MapClaims{}

rtc[constants.UserIdKey] = token.UserId
rtc[constants.ExpireTimeKey] = td.RefreshTokenExpireTime

rt := jwt.NewWithClaims(jwt.SigningMethodHS256, rtc)

td.RefreshToken, err = rt.SignedString([]byte(os.Getenv(constants.RefreshTokenSecretKey)))
if err != nil {
return nil, err
}

return td, err
}
41 changes: 39 additions & 2 deletions src/services/user_front_service.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package services

import (
"errors"
"fmt"
"github.com/alireza-fa/blog-go/src/api/dto"
"github.com/alireza-fa/blog-go/src/constants"
"github.com/alireza-fa/blog-go/src/data/cache"
"github.com/alireza-fa/blog-go/src/data/db"
"github.com/alireza-fa/blog-go/src/data/models"
Expand All @@ -20,6 +22,7 @@ type UserFrontService struct {
otpService *OtpService
redisClient *redis.Client
notification notification.Notifier
tokenService *TokenService
database *gorm.DB
}

Expand All @@ -29,6 +32,7 @@ func NewUserFrontService() *UserFrontService {
otpService: NewOtpService(),
redisClient: cache.GetRedis(),
notification: notification.NewNotifier(),
tokenService: NewTokenService(),
database: db.GetDb(),
}
}
Expand Down Expand Up @@ -82,29 +86,62 @@ func (service *UserFrontService) VerifyUser(userVerify *dto.UserVerify) (*models
user.Password = string(bytePassword)

database := service.database.Begin()

if err := database.Create(&user).Error; err != nil {
database.Rollback()
service.logger.Error(logging.Postgres, logging.Rollback, err.Error(), nil)
}
var defaultRole models.Role
if err := database.
Model(models.Role{}).
Where("name = ?", constants.DefaultRole).
Find(&defaultRole).Error; err != nil {
database.Rollback()
service.logger.Error(logging.Postgres, logging.Rollback, "default role not found"+err.Error(), nil)
return nil, err
}
userRole := models.UserRole{UserId: user.Id, RoleId: defaultRole.Id}
database.Create(&userRole)

database.Commit()

return &user, nil
}

func (service *UserFrontService) UserLogin(userLogin dto.UserLogin) (*models.User, error) {
func (service *UserFrontService) UserLogin(userLogin dto.UserLogin) (*dto.TokenDetail, error) {
var user models.User

if err := service.database.
Model(&models.User{}).
Where("user_name = ?", userLogin.UserName).
Preload("UserRoles", func(tx *gorm.DB) *gorm.DB {
return tx.Preload("Role")
}).
Find(&user).Error; err != nil {
return nil, err
}

if user.UserName == "" {
return nil, errors.New("user with this information not found")
}

err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(userLogin.Password))
if err != nil {
return nil, err
}

return &user, nil
tokenDto := TokenDto{
UserId: user.Id,
FullName: user.FullName,
UserName: user.UserName,
Email: user.Email,
}

if len(*user.UserRoles) > 0 {
for _, ur := range *user.UserRoles {
tokenDto.Roles = append(tokenDto.Roles, ur.Role.Name)
}
}

return service.tokenService.GenerateToken(&tokenDto)
}

0 comments on commit 4d909a4

Please sign in to comment.