diff --git a/internal/account/entity.go b/internal/account/entity.go index 177eb69..f5e517d 100644 --- a/internal/account/entity.go +++ b/internal/account/entity.go @@ -4,4 +4,5 @@ type User struct { ID uint `gorm:"primaryKey" json:"id"` Username string `gorm:"unique" json:"username"` Password string `json:"-"` + Token string `json:"-"` } diff --git a/internal/account/repo.go b/internal/account/repo.go index f13d03e..113b320 100644 --- a/internal/account/repo.go +++ b/internal/account/repo.go @@ -48,3 +48,17 @@ func (ur *UserRepository) FindByUsername(username string) (*User, error) { } return &user, nil } + +func (ur *UserRepository) Login(id uint, token string) error { + if err := ur.db.Model(&User{}).Where("id = ?", id).Update("token", token).Error; err != nil { + return err + } + return nil +} + +func (ur *UserRepository) Logout(id uint, token string) error { + if err := ur.db.Model(&User{}).Where("id = ?", id).Update("token", "").Error; err != nil { + return err + } + return nil +} diff --git a/internal/account/service.go b/internal/account/service.go index 59b609b..e60a893 100644 --- a/internal/account/service.go +++ b/internal/account/service.go @@ -1,6 +1,11 @@ package account -import "golang.org/x/crypto/bcrypt" +import ( + "errors" + "feedsystem_video_go/internal/auth" + + "golang.org/x/crypto/bcrypt" +) type UserService struct { userRepository *UserRepository @@ -62,3 +67,34 @@ func (us *UserService) FindByUsername(username string) (*User, error) { return user, nil } } + +func (us *UserService) Login(username, password string) (string, error) { + user, err := us.FindByUsername(username) + if err != nil { + return "", err + } + if err := bcrypt.CompareHashAndPassword([]byte(user.Password), []byte(password)); err != nil { + return "", err + } + // generate token + token, err := auth.GenerateToken(user.ID, user.Username) + if err != nil { + return "", err + } + if err := us.userRepository.Login(user.ID, token); err != nil { + return "", err + } + + return token, nil +} + +func (us *UserService) Logout(userID uint) error { + user, err := us.FindByID(userID) + if err != nil { + return err + } + if user.Token == "" { + return errors.New("user already logged out") + } + return us.userRepository.Logout(user.ID, user.Token) +} diff --git a/internal/http/account_handler.go b/internal/http/account_handler.go index baf386e..1dd661c 100644 --- a/internal/http/account_handler.go +++ b/internal/http/account_handler.go @@ -53,6 +53,19 @@ type ChangePasswordRequest struct { type ChangePasswordResponse struct { } +type LoginRequest struct { + Username string `json:"username"` + Password string `json:"password"` +} +type LoginResponse struct { + Token string `json:"token"` +} +type LogoutRequest struct { + ID uint `json:"id"` +} +type LogoutResponse struct { +} + func NewUserHandler(userService *account.UserService) *UserHandler { return &UserHandler{userService: userService} } @@ -91,7 +104,7 @@ func (h *UserHandler) ChangePassword(c *gin.Context) { c.JSON(400, gin.H{"error": err.Error()}) return } - if err := h.userService.ChangePassword(req.ID, req.NewPassword); err != nil { + if err := h.userService.ChangePassword(req.Username, req.OldPassword, req.NewPassword); err != nil { c.JSON(500, gin.H{"error": err.Error()}) return } @@ -125,3 +138,30 @@ func (h *UserHandler) FindByUsername(c *gin.Context) { c.JSON(200, user) } } + +func (h *UserHandler) Login(c *gin.Context) { + var req LoginRequest + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(400, gin.H{"error": err.Error()}) + return + } + if token, err := h.userService.Login(req.Username, req.Password); err != nil { + c.JSON(500, gin.H{"error": err.Error()}) + return + } else { + c.JSON(200, LoginResponse{Token: token}) + } +} + +func (h *UserHandler) Logout(c *gin.Context) { + var req LogoutRequest + if err := c.ShouldBindJSON(&req); err != nil { + c.JSON(400, gin.H{"error": err.Error()}) + return + } + if err := h.userService.Logout(req.ID); err != nil { + c.JSON(500, gin.H{"error": err.Error()}) + return + } + c.JSON(200, LogoutResponse{}) +} diff --git a/internal/http/router.go b/internal/http/router.go index cddcd63..29de74a 100644 --- a/internal/http/router.go +++ b/internal/http/router.go @@ -2,6 +2,7 @@ package http import ( "feedsystem_video_go/internal/account" + "feedsystem_video_go/internal/middleware" "github.com/gin-gonic/gin" "gorm.io/gorm" @@ -21,6 +22,16 @@ func SetRouter(db *gorm.DB) *gin.Engine { userGroup.POST("/findByID", userHandler.FindByID) userGroup.POST("/findByUsername", userHandler.FindByUsername) } + authGroup := r.Group("/auth") + { + authGroup.POST("/login", userHandler.Login) + } + + protectedAuthGroup := authGroup.Group("") + protectedAuthGroup.Use(middleware.JWTAuth()) + { + protectedAuthGroup.POST("/logout", userHandler.Logout) + } return r }