This commit is contained in:
vipg
2026-02-09 16:49:18 +08:00
parent 6640f09639
commit bdb1065217
6 changed files with 261 additions and 141 deletions

View File

@@ -0,0 +1,92 @@
package service
import (
"database/sql"
"errors"
"github.com/jackc/pgconn"
"golang.org/x/crypto/bcrypt"
"user/internal/repository"
)
var (
ErrInvalidInput = errors.New("invalid_input")
ErrAccountExists = errors.New("account_exists")
ErrUnauthorized = errors.New("unauthorized")
)
type Service struct {
Repo *repository.Repo
}
func New(repo *repository.Repo) *Service {
return &Service{Repo: repo}
}
func (s *Service) Register(account, password string) (string, error) {
if !validAccount(account) || !validPassword(password) {
return "", ErrInvalidInput
}
hashed, err := bcrypt.GenerateFromPassword([]byte(password), 12)
if err != nil {
return "", err
}
tx, err := s.Repo.DB.Begin()
if err != nil {
return "", err
}
defer func() { _ = tx.Rollback() }()
userID, err := s.Repo.CreateUser(tx)
if err != nil {
return "", err
}
if err := s.Repo.CreateLoginAccount(tx, userID, account); err != nil {
if isUniqueViolation(err) {
return "", ErrAccountExists
}
return "", err
}
if err := s.Repo.CreateLoginPassword(tx, userID, string(hashed)); err != nil {
return "", err
}
if err := tx.Commit(); err != nil {
return "", err
}
return userID, nil
}
func (s *Service) Login(account, password string) (string, error) {
if !validAccount(account) || !validPassword(password) {
return "", ErrInvalidInput
}
userID, err := s.Repo.GetUserIDByAccount(account)
if err != nil {
return "", ErrUnauthorized
}
hashed, err := s.Repo.GetHashedPassword(userID)
if err != nil {
return "", ErrUnauthorized
}
if bcrypt.CompareHashAndPassword([]byte(hashed), []byte(password)) != nil {
return "", ErrUnauthorized
}
return userID, nil
}
func validAccount(a string) bool {
n := len(a)
return n >= 3 && n <= 100
}
func validPassword(p string) bool {
n := len(p)
return n >= 8 && n <= 128
}
func isUniqueViolation(err error) bool {
var pe *pgconn.PgError
if errors.As(err, &pe) {
return pe.Code == "23505"
}
return false
}