95 lines
2.2 KiB
Go
95 lines
2.2 KiB
Go
package service
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/golang-jwt/jwt/v5"
|
|
"golang.org/x/crypto/bcrypt"
|
|
"net/http"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
|
|
"git.urec56.ru/urec/chat_back_go/config"
|
|
"git.urec56.ru/urec/chat_back_go/internal/domain"
|
|
"git.urec56.ru/urec/chat_back_go/internal/logger"
|
|
)
|
|
|
|
const maxBcryptPasswordLen = 72
|
|
|
|
type authService struct {
|
|
cfg config.JWT
|
|
parser Parser
|
|
l *logger.Logger
|
|
}
|
|
|
|
func newAuthService(cfg config.JWT, l *logger.Logger) *authService {
|
|
return &authService{cfg: cfg, parser: jwt.NewParser(), l: l}
|
|
}
|
|
|
|
func (s *authService) keyFunc(*jwt.Token) (interface{}, error) {
|
|
return s.cfg.SecretKey, nil
|
|
}
|
|
|
|
func (s *authService) ExtractAuthToken(r *http.Request) (string, error) {
|
|
token := r.Header.Get("Authorization")
|
|
|
|
tokenData := strings.Split(token, " ")
|
|
if len(tokenData) != 2 || strings.ToLower(tokenData[0]) != "bearer" {
|
|
return "", domain.TokenError
|
|
|
|
}
|
|
|
|
return tokenData[1], nil
|
|
}
|
|
|
|
func (s *authService) DecodeAuthToken(token string) (int, error) {
|
|
val, err := s.parser.Parse(token, s.keyFunc)
|
|
if err != nil {
|
|
return 0, domain.TokenError
|
|
}
|
|
|
|
sub, err := val.Claims.GetSubject()
|
|
if err != nil {
|
|
return 0, domain.TokenError
|
|
}
|
|
|
|
userID, err := strconv.Atoi(sub)
|
|
if err != nil {
|
|
return 0, domain.TokenError
|
|
}
|
|
|
|
return userID, nil
|
|
}
|
|
|
|
func (s *authService) EncodeAuthToken(userID int) (string, error) {
|
|
claims := jwt.MapClaims{
|
|
"sub": fmt.Sprintf("%d", userID),
|
|
"iat": time.Now().Unix(),
|
|
"exp": time.Now().Add(time.Hour * 24 * 30).Unix(), // срок действия 30 дней
|
|
}
|
|
|
|
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
|
|
|
|
tokenString, err := token.SignedString(s.cfg.SecretKey)
|
|
if err != nil {
|
|
s.l.Errorf("singing jwt: %v", err)
|
|
return "", domain.InternalServerError
|
|
}
|
|
return tokenString, nil
|
|
}
|
|
|
|
func (s *authService) HashPassword(p string) (string, error) {
|
|
hash, err := bcrypt.GenerateFromPassword([]byte(p)[:maxBcryptPasswordLen], bcrypt.DefaultCost)
|
|
if err != nil {
|
|
s.l.Errorf("error during password hashing: %s", err)
|
|
return "", domain.HashingError
|
|
}
|
|
return string(hash), nil
|
|
}
|
|
|
|
func (s *authService) VerifyHashedPassword(p, hp string) bool {
|
|
if err := bcrypt.CompareHashAndPassword([]byte(hp), []byte(p)); err != nil {
|
|
return false
|
|
}
|
|
return true
|
|
}
|