Skip to content

Commit

Permalink
feat: integrate refresh token with model
Browse files Browse the repository at this point in the history
  • Loading branch information
crazyoptimist committed Jun 17, 2024
1 parent 8c166e3 commit add7e89
Show file tree
Hide file tree
Showing 6 changed files with 92 additions and 95 deletions.
14 changes: 7 additions & 7 deletions internal/domain/auth/dto.go
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
package auth

type LoginDto struct {
Email string `json:"email" binding:"required"`
Password string `json:"password" binding:"required"`
}

type LoginResponse struct {
AccessToken string `json:"accessToken"`
RefreshToken string `json:"refreshToken"`
ExpiresIn float64 `json:"expiresIn"`
}

type LoginDto struct {
Email string `json:"email" binding:"required"`
Password string `json:"password" binding:"required"`
}

type LogoutDto struct {
RefreshToken string `json:"refreshToken" binding:"required"`
type RefreshDto struct {
RefreshToken string `json:"refreshToken"`
}

type RegisterDto struct {
Expand Down
70 changes: 45 additions & 25 deletions internal/domain/auth/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,25 +4,33 @@ import (
"errors"
"strconv"

"gin-starter/internal/config"
"gin-starter/internal/domain/model"
"gin-starter/internal/domain/user"
"gin-starter/pkg/common"
"gin-starter/pkg/utils"
)

type AuthHelper interface {
BlacklistToken(token string) error
IsTokenBlacklisted(token string) (bool, error)
type UserRepository interface {
FindAll(
paginationParam common.PaginationParam,
sortParams []common.SortParam,
filterParams []common.FilterParam,
) ([]model.User, int64, error)
FindById(id int) (*model.User, error)
FindByEmail(email string) (*model.User, error)
Create(user model.User) (*model.User, error)
Update(user model.User) (*model.User, error)
Delete(user model.User) error
UpdateRefreshToken(userId int, refreshToken string) error
}

type AuthService struct {
UserRepository user.UserRepository
AuthHelper AuthHelper
UserRepository UserRepository
}

func NewAuthService(userRepository user.UserRepository, authHelper AuthHelper) *AuthService {
func NewAuthService(userRepository UserRepository) *AuthService {
return &AuthService{
UserRepository: userRepository,
AuthHelper: authHelper,
}
}

Expand Down Expand Up @@ -59,6 +67,7 @@ func (s *AuthService) Register(registerDto *RegisterDto) (*LoginResponse, error)
return &LoginResponse{
AccessToken: accessToken,
RefreshToken: refreshToken,
ExpiresIn: config.Global.JwtAccessTokenExpiresIn.Seconds(),
}, nil
}

Expand All @@ -77,50 +86,61 @@ func (s *AuthService) Login(loginDto *LoginDto) (*LoginResponse, error) {
return nil, err
}

return &LoginResponse{AccessToken: accessToken, RefreshToken: refreshToken}, nil
if err := s.UserRepository.UpdateRefreshToken(
user.ID,
refreshToken,
); err != nil {
return nil, err
}

return &LoginResponse{
AccessToken: accessToken,
RefreshToken: refreshToken,
ExpiresIn: config.Global.JwtAccessTokenExpiresIn.Seconds(),
}, nil
}

func (s *AuthService) Logout(logoutDto *LogoutDto) error {
return s.AuthHelper.BlacklistToken(logoutDto.RefreshToken)
func (s *AuthService) Logout(user model.User) error {
err := s.UserRepository.UpdateRefreshToken(user.ID, "")
return err
}

func (s *AuthService) Refresh(logoutDto *LogoutDto) (*LoginResponse, error) {
func (s *AuthService) Refresh(dto *RefreshDto) (*LoginResponse, error) {

isTokenValid, userIdString, keyId, err := ValidateJwtToken(logoutDto.RefreshToken)
_, userIdString, _, err := ValidateJwtToken(dto.RefreshToken)
if err != nil {
return nil, err
}

if !isTokenValid {
return nil, errors.New("Invalid refresh token")
}

if keyId != RefreshTokenKeyId {
return nil, errors.New("Invalid key ID")
userId, err := strconv.Atoi(userIdString)
if err != nil {
return nil, err
}

isTokenBlacklisted, err := s.AuthHelper.IsTokenBlacklisted(logoutDto.RefreshToken)
user, err := s.UserRepository.FindById(userId)
if err != nil {
return nil, err
}

if isTokenBlacklisted {
if *user.RefreshToken != dto.RefreshToken {
return nil, errors.New("Invalid refresh token")
}

err = s.AuthHelper.BlacklistToken(logoutDto.RefreshToken)
accessToken, refreshToken, err := GenerateTokenPair(userId)
if err != nil {
return nil, err
}

userId, err := strconv.Atoi(userIdString)
accessToken, refreshToken, err := GenerateTokenPair(userId)
if err != nil {
if err := s.UserRepository.UpdateRefreshToken(
userId,
refreshToken,
); err != nil {
return nil, err
}

return &LoginResponse{
AccessToken: accessToken,
RefreshToken: refreshToken,
ExpiresIn: config.Global.JwtAccessTokenExpiresIn.Seconds(),
}, nil
}
25 changes: 13 additions & 12 deletions internal/infrastructure/controller/auth_controller.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
package controller

import (
"errors"
"net/http"

"github.com/gin-gonic/gin"
"gorm.io/gorm"

"gin-starter/internal/config"
"gin-starter/internal/domain/auth"
"gin-starter/internal/infrastructure/helper"
"gin-starter/internal/domain/model"
"gin-starter/internal/infrastructure/repository"
"gin-starter/pkg/common"
)
Expand All @@ -19,8 +19,7 @@ type authController struct {

func NewAuthController(db *gorm.DB) *authController {
userRepository := repository.NewUserRepository(db)
authHelper := helper.NewAuthHelper()
authService := auth.NewAuthService(userRepository, authHelper)
authService := auth.NewAuthService(userRepository)
return &authController{AuthService: *authService}
}

Expand All @@ -44,7 +43,6 @@ func (a *authController) Register(c *gin.Context) {
common.RaiseHttpError(c, http.StatusBadRequest, err)
return
}
loginResponse.ExpiresIn = config.Global.JwtAccessTokenExpiresIn.Seconds()

c.JSON(http.StatusCreated, loginResponse)
}
Expand All @@ -70,27 +68,30 @@ func (a *authController) Login(c *gin.Context) {
common.RaiseHttpError(c, http.StatusUnauthorized, err)
return
}
loginResponse.ExpiresIn = config.Global.JwtAccessTokenExpiresIn.Seconds()

c.JSON(http.StatusCreated, loginResponse)
}

// Logout godoc
// @Summary Logout user (Invalidates refresh token)
// @Summary Logout user
// @Tags auth
// @Success 200
// @Failure 401 {object} common.HttpError
// @Failure 500 {object} common.HttpError
// @Router /auth/logout [post]
// @Security JWT
func (a *authController) Logout(c *gin.Context) {
var logoutDto auth.LogoutDto
if err := c.BindJSON(&logoutDto); err != nil {
common.RaiseHttpError(c, http.StatusBadRequest, err)
user, exists := c.Get("user")
if !exists {
common.RaiseHttpError(
c,
http.StatusInternalServerError,
errors.New("User missing in context"),
)
return
}

if err := a.AuthService.Logout(&logoutDto); err != nil {
if err := a.AuthService.Logout(user.(model.User)); err != nil {
common.RaiseHttpError(c, http.StatusInternalServerError, err)
return
}
Expand All @@ -107,7 +108,7 @@ func (a *authController) Logout(c *gin.Context) {
// @Failure 500 {object} common.HttpError
// @Router /auth/refresh [post]
func (a *authController) Refresh(c *gin.Context) {
var refreshDto auth.LogoutDto
var refreshDto auth.RefreshDto
if err := c.BindJSON(&refreshDto); err != nil {
common.RaiseHttpError(c, http.StatusBadRequest, err)
return
Expand Down
42 changes: 0 additions & 42 deletions internal/infrastructure/helper/auth_helper.go

This file was deleted.

34 changes: 26 additions & 8 deletions internal/infrastructure/repository/user_repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,14 @@ func (u *userRepository) FindById(id int) (*model.User, error) {
return &user, err
}

func (u *userRepository) FindByEmail(email string) (*model.User, error) {
var user model.User

err := u.DB.Where("email = ?", email).First(&user).Error

return &user, err
}

func (u *userRepository) Create(user model.User) (*model.User, error) {
err := u.DB.Save(&user).Error
if err != nil {
Expand All @@ -105,14 +113,24 @@ func (u *userRepository) Update(user model.User) (*model.User, error) {
return &user, nil
}

func (u *userRepository) Delete(user model.User) error {
return u.DB.Delete(&user).Error
}

func (u *userRepository) FindByEmail(email string) (*model.User, error) {
var user model.User
func (u *userRepository) UpdateRefreshToken(userId int, refreshToken string) error {
err := u.DB.Model(
&model.User{},
).Where(
"id = ?",
userId,
).Updates(
map[string]interface{}{
"RefreshToken": refreshToken,
},
).Error
if err != nil {
return err
}

err := u.DB.Where("email = ?", email).First(&user).Error
return nil
}

return &user, err
func (u *userRepository) Delete(user model.User) error {
return u.DB.Delete(&user).Error
}
2 changes: 1 addition & 1 deletion internal/infrastructure/server/router.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ func registerAuthRoutes(g *gin.RouterGroup) {
controllers := controller.NewAuthController(config.Global.DB)
g.POST("/register", controllers.Register)
g.POST("/login", controllers.Login)
g.POST("/logout", controllers.Logout, middleware.AuthMiddleware())
g.POST("/logout", middleware.AuthMiddleware(), controllers.Logout)
g.POST("/refresh", controllers.Refresh)
}

Expand Down

0 comments on commit add7e89

Please sign in to comment.