All checks were successful
Server CI/CD / deploy (push) Successful in 37s
- Register 서비스 메서드 추가 (중복 아이디 체크, bcrypt 해시, role: user로 생성) - Register 핸들러 추가 (빈값, 6자 미만 비밀번호 유효성 검사) - /api/auth/register 라우트 등록 (public) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
109 lines
2.8 KiB
Go
109 lines
2.8 KiB
Go
package auth
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"a301_server/pkg/config"
|
|
"github.com/golang-jwt/jwt/v5"
|
|
"github.com/redis/go-redis/v9"
|
|
"golang.org/x/crypto/bcrypt"
|
|
)
|
|
|
|
type Claims struct {
|
|
UserID uint `json:"user_id"`
|
|
Username string `json:"username"`
|
|
Role string `json:"role"`
|
|
jwt.RegisteredClaims
|
|
}
|
|
|
|
type Service struct {
|
|
repo *Repository
|
|
rdb *redis.Client
|
|
}
|
|
|
|
func NewService(repo *Repository, rdb *redis.Client) *Service {
|
|
return &Service{repo: repo, rdb: rdb}
|
|
}
|
|
|
|
func (s *Service) Login(username, password string) (string, *User, error) {
|
|
user, err := s.repo.FindByUsername(username)
|
|
if err != nil {
|
|
return "", nil, fmt.Errorf("아이디 또는 비밀번호가 올바르지 않습니다")
|
|
}
|
|
|
|
if err := bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(password)); err != nil {
|
|
return "", nil, fmt.Errorf("아이디 또는 비밀번호가 올바르지 않습니다")
|
|
}
|
|
|
|
expiry := time.Duration(config.C.JWTExpiryHours) * time.Hour
|
|
claims := &Claims{
|
|
UserID: user.ID,
|
|
Username: user.Username,
|
|
Role: string(user.Role),
|
|
RegisteredClaims: jwt.RegisteredClaims{
|
|
ExpiresAt: jwt.NewNumericDate(time.Now().Add(expiry)),
|
|
IssuedAt: jwt.NewNumericDate(time.Now()),
|
|
},
|
|
}
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
|
tokenStr, err := token.SignedString([]byte(config.C.JWTSecret))
|
|
if err != nil {
|
|
return "", nil, fmt.Errorf("토큰 생성에 실패했습니다")
|
|
}
|
|
|
|
// Redis에 세션 저장 (1계정 1세션)
|
|
key := fmt.Sprintf("session:%d", user.ID)
|
|
s.rdb.Set(context.Background(), key, tokenStr, expiry)
|
|
|
|
return tokenStr, user, nil
|
|
}
|
|
|
|
func (s *Service) Logout(userID uint) {
|
|
key := fmt.Sprintf("session:%d", userID)
|
|
s.rdb.Del(context.Background(), key)
|
|
}
|
|
|
|
func (s *Service) GetAllUsers() ([]User, error) {
|
|
return s.repo.FindAll()
|
|
}
|
|
|
|
func (s *Service) UpdateRole(id string, role Role) error {
|
|
return s.repo.UpdateRole(id, role)
|
|
}
|
|
|
|
func (s *Service) DeleteUser(id string) error {
|
|
return s.repo.Delete(id)
|
|
}
|
|
|
|
func (s *Service) Register(username, password string) error {
|
|
if _, err := s.repo.FindByUsername(username); err == nil {
|
|
return fmt.Errorf("이미 사용 중인 아이디입니다")
|
|
}
|
|
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return fmt.Errorf("비밀번호 처리에 실패했습니다")
|
|
}
|
|
return s.repo.Create(&User{
|
|
Username: username,
|
|
PasswordHash: string(hash),
|
|
Role: RoleUser,
|
|
})
|
|
}
|
|
|
|
func (s *Service) EnsureAdmin(username, password string) error {
|
|
if _, err := s.repo.FindByUsername(username); err == nil {
|
|
return nil // 이미 존재하면 스킵
|
|
}
|
|
hash, err := bcrypt.GenerateFromPassword([]byte(password), bcrypt.DefaultCost)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return s.repo.Create(&User{
|
|
Username: username,
|
|
PasswordHash: string(hash),
|
|
Role: RoleAdmin,
|
|
})
|
|
}
|