Добавлен основные классы для сервиса авторизаци

This commit is contained in:
Ганеев Артем
2025-10-28 20:49:54 +03:00
parent def3552a67
commit 736b8031f8
26 changed files with 904 additions and 40 deletions

142
internal/service/auth.go Normal file
View File

@@ -0,0 +1,142 @@
package service
import (
"authorization/internal"
"authorization/internal/config"
"crypto/sha1"
"errors"
"fmt"
"time"
"github.com/golang-jwt/jwt"
)
const (
refresh = "refresh"
access = "access"
)
type tokenClaims struct {
jwt.StandardClaims
UserId int `json:"user_id"`
UserRole string `json:"user_role"`
TokenType string `json:"token_type"`
}
type AuthService struct {
userService UserService
tokenConfigs config.TokenConfig
}
func newAuthService(userService UserService) *AuthService {
return &AuthService{userService: userService}
}
func (s *AuthService) CreateUser(user internal.User) (int, error) {
user.Password = s.generatePasswordHash(user.Password)
return s.userService.CreateUser(user)
}
func (s *AuthService) GenerateToken(username string, password string) (string, string, error) {
user, err := s.userService.GetUser(username, s.generatePasswordHash(password))
if err != nil {
return "", "", err
}
accessTokenClaims := s.generateClaims(user.Id, user.UserRole, access)
refreshTokenClaims := s.generateClaims(user.Id, user.UserRole, refresh)
accessToken, err := accessTokenClaims.SignedString([]byte(s.tokenConfigs.AccessToken.GetSecretBytes()))
if err != nil {
return "", "", err
}
refreshToken, err := refreshTokenClaims.SignedString([]byte(s.tokenConfigs.RefreshToken.GetSecretBytes()))
if err != nil {
return "", "", err
}
return accessToken, refreshToken, nil
}
func (s *AuthService) ChangeUserRole(username string, userrole string) (string, error) {
user, err := s.userService.ChangeUserRole(username, userrole)
if err != nil {
return "", err
}
return user, nil
}
func (s *AuthService) generateClaims(userId int, userRole string, tokenType string) *jwt.Token {
tokenTTL := s.tokenConfigs.RefreshToken.GetTTL()
if tokenType == access {
tokenTTL = s.tokenConfigs.AccessToken.GetTTL()
}
return jwt.NewWithClaims(jwt.SigningMethodHS256, &tokenClaims{
jwt.StandardClaims{
ExpiresAt: time.Now().Add(tokenTTL).Unix(),
IssuedAt: time.Now().Unix(),
},
userId,
userRole,
tokenType,
})
}
func (s *AuthService) generatePasswordHash(password string) string {
hash := sha1.New()
hash.Write([]byte(password))
return fmt.Sprintf("%x", hash)
}
func (s *AuthService) ParseToken(accessToken string) (string, error) {
claims, err := s.parseTokenWithSecret(accessToken, s.tokenConfigs.AccessToken.GetSecretBytes())
if err != nil {
return "", err
}
return claims.UserRole, nil
}
func (s *AuthService) RefreshToken(refreshToken string) (string, string, error) {
// Парсим refresh token
claims, err := s.parseTokenWithSecret(refreshToken, s.tokenConfigs.RefreshToken.GetSecretBytes())
if err != nil {
return "", "", errors.New("invalid refresh token")
}
// Проверяем, что это именно refresh token
if claims.TokenType != refresh {
return "", "", errors.New("token is not a refresh token")
}
// Генерируем новую пару токенов
newAccessTokenClaims := s.generateClaims(claims.UserId, claims.UserRole, access)
newRefreshTokenClaims := s.generateClaims(claims.UserId, claims.UserRole, refresh)
newAccessToken, err := newAccessTokenClaims.SignedString([]byte(s.tokenConfigs.AccessToken.GetSecretBytes()))
if err != nil {
return "", "", err
}
newRefreshToken, err := newRefreshTokenClaims.SignedString([]byte(s.tokenConfigs.RefreshToken.GetSecretBytes()))
if err != nil {
return "", "", err
}
return newAccessToken, newRefreshToken, nil
}
// parseTokenWithSecret - общий метод для парсинга токена с заданным секретным ключом
func (s *AuthService) parseTokenWithSecret(tokenString string, secret []byte) (*tokenClaims, error) {
token, err := jwt.ParseWithClaims(tokenString, &tokenClaims{}, func(t *jwt.Token) (interface{}, error) {
return secret, nil
})
if err != nil {
return nil, err
}
claims, ok := token.Claims.(*tokenClaims)
if !ok {
return nil, errors.New("invalid token claims")
}
return claims, nil
}