learnsteam-quiz-api/internal/services/token.go

201 lines
5.2 KiB
Go
Raw Normal View History

2023-10-19 22:47:12 +09:00
package services
import (
2023-11-17 01:38:01 +09:00
"errors"
2023-10-19 22:47:12 +09:00
"fmt"
"strings"
2023-11-17 01:38:01 +09:00
"time"
2023-10-19 22:47:12 +09:00
2023-11-17 01:38:01 +09:00
config "learnsteam/learsteam-quiz-api/configs"
"learnsteam/learsteam-quiz-api/internal/models"
"learnsteam/learsteam-quiz-api/internal/repositories"
2023-10-19 22:47:12 +09:00
"github.com/golang-jwt/jwt/v5"
2023-11-17 01:38:01 +09:00
"github.com/google/uuid"
2023-10-19 22:47:12 +09:00
)
type tokenService struct {
repository repositories.TokenRepository
}
type TokenService interface {
Find(string) (*models.Token, error)
2023-11-17 01:38:01 +09:00
Create(string) (*models.Token, error)
2023-10-19 22:47:12 +09:00
Update(*models.Token) (*models.Token, error)
Delete(string) error
2023-11-17 01:38:01 +09:00
Refresh(string) (*models.Token, error)
2023-10-19 22:47:12 +09:00
Generate(string, int64) (string, error)
Verify(tokenString string) (*jwt.Token, error)
GetJwtToken(string) (*jwt.Token, error)
ExtractTokenString(string) string
VerifyTokenString(string) (*jwt.Token, error)
ValidToken(*jwt.Token) (bool, error)
}
func NewTokenService(repository repositories.TokenRepository) TokenService {
return &tokenService{
repository: repository,
}
}
func (s *tokenService) Find(id string) (*models.Token, error) {
return s.repository.Find(id)
}
2023-11-17 01:38:01 +09:00
func (s *tokenService) Create(sub string) (*models.Token, error) {
expiredAt := time.Now().Add(time.Hour * 24 * 30)
accessToken, err := s.repository.Generate(sub, expiredAt.Unix())
if err != nil {
return nil, err
}
refreshExpiredAt := time.Now().Add(time.Hour * 24 * 90)
refreshToken, err := s.repository.Generate(sub, refreshExpiredAt.Unix())
if err != nil {
return nil, err
}
newToken := &models.Token{
ID: uuid.NewString(),
UserID: sub,
Token: accessToken,
RefreshToken: refreshToken,
Expires: expiredAt.Unix(),
RefreshExpires: refreshExpiredAt.Unix(),
}
token, err := s.repository.Create(newToken)
return token, err
2023-10-19 22:47:12 +09:00
}
func (s *tokenService) Update(token *models.Token) (*models.Token, error) {
return s.repository.Update(token)
}
func (s *tokenService) Delete(id string) error {
return s.repository.Delete(id)
}
func (s *tokenService) Verify(tokenString string) (*jwt.Token, error) {
jwtToken, err := jwt.Parse(tokenString, func(jwtToken *jwt.Token) (interface{}, error) {
if _, ok := jwtToken.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", jwtToken.Header["alg"])
}
return []byte(config.SECRET_KEY), nil
})
return jwtToken, err
}
func (s *tokenService) Generate(user_id string, expire_at int64) (string, error) {
claims := jwt.MapClaims{}
claims["authorized"] = true
claims["sub"] = user_id
claims["exp"] = expire_at
at := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
token, err := at.SignedString([]byte(config.SECRET_KEY))
return token, err
}
func (s *tokenService) GetJwtToken(tokenString string) (*jwt.Token, error) {
jwtToken, err := jwt.Parse(tokenString, func(jwtToken *jwt.Token) (interface{}, error) {
if _, ok := jwtToken.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", jwtToken.Header["alg"])
}
return []byte(config.SECRET_KEY), nil
})
return jwtToken, err
}
func (s *tokenService) ExtractTokenString(authorization string) string {
strArr := strings.Split(authorization, " ")
if len(strArr) == 2 {
return strArr[1]
}
return ""
}
func (s *tokenService) VerifyTokenString(tokenString string) (*jwt.Token, error) {
jwtToken, err := jwt.Parse(tokenString, func(jwtToken *jwt.Token) (interface{}, error) {
if _, ok := jwtToken.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", jwtToken.Header["alg"])
}
return []byte(config.SECRET_KEY), nil
})
if err != nil {
return nil, err
}
return jwtToken, nil
}
func (s *tokenService) ValidToken(jwtToken *jwt.Token) (bool, error) {
if jwtToken == nil {
return false, fmt.Errorf("no token")
}
return jwtToken.Valid, nil
}
2023-11-17 01:38:01 +09:00
func (s *tokenService) Refresh(refreshToken string) (*models.Token, error) {
fmt.Println("refresh_token", refreshToken)
jwtToken, err := jwt.Parse(refreshToken, func(jwtToken *jwt.Token) (interface{}, error) {
if _, ok := jwtToken.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", jwtToken.Header["alg"])
}
return []byte(config.SECRET_KEY), nil
})
if err != nil {
fmt.Println("refresh token is not valid")
} else {
fmt.Println("refresh token is valid")
}
if err != nil {
fmt.Println("error", err.Error())
return nil, err
}
claims, ok := jwtToken.Claims.(jwt.MapClaims)
if !ok || !jwtToken.Valid {
return nil, errors.New("refresh token is invalid")
}
sub := fmt.Sprintf("%s", claims["sub"])
if err != nil {
return nil, errors.New("wrong user")
}
token, err := s.repository.FindByRefreshToken(sub, refreshToken)
if err != nil {
return nil, errors.New("wrong token")
}
expiredAt := time.Now().Add(time.Hour * 24 * 30)
accessToken, err := s.repository.Generate(sub, expiredAt.Unix())
if err != nil {
return nil, err
}
refreshExpiredAt := time.Now().Add(time.Hour * 24 * 90)
refreshToken, err = s.repository.Generate(sub, refreshExpiredAt.Unix())
if err != nil {
return nil, err
}
token.Token = accessToken
token.Expires = expiredAt.Unix()
token.RefreshToken = refreshToken
token.RefreshExpires = refreshExpiredAt.Unix()
return s.repository.Update(token)
}