cslms-api/internal/services/token.go

200 lines
5.1 KiB
Go
Raw Permalink Normal View History

2023-12-27 17:31:49 +09:00
package services
import (
"errors"
"fmt"
"strings"
"time"
config "learnsteam/cslms-api/configs"
"learnsteam/cslms-api/internal/models"
"learnsteam/cslms-api/internal/repositories"
"github.com/golang-jwt/jwt/v5"
)
type tokenService struct {
repository repositories.TokenRepository
}
type TokenService interface {
Find(int64) (*models.Token, error)
Create(int64, string) (*models.Token, error)
Update(*models.Token) (*models.Token, error)
Delete(string) error
Refresh(string) (*models.Token, error)
2023-12-29 00:27:12 +09:00
Generate(int64, int64, string) (string, error)
Verify(string) (*jwt.Token, error)
Invalid(int64, string) error
2023-12-27 17:31:49 +09:00
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 int64) (*models.Token, error) {
return s.repository.Find(id)
}
func (s *tokenService) Create(user_id int64, role string) (*models.Token, error) {
expiredAt := time.Now().Add(time.Hour * 24 * 30)
accessToken, err := s.repository.Generate(user_id, expiredAt.Unix(), role)
if err != nil {
return nil, err
}
refreshExpiredAt := time.Now().Add(time.Hour * 24 * 90)
refreshToken, err := s.repository.Generate(user_id, refreshExpiredAt.Unix(), role)
if err != nil {
return nil, err
}
newToken := &models.Token{
UserID: user_id,
Token: accessToken,
RefreshToken: refreshToken,
Status: "on",
EndingAt: expiredAt,
RegisterAt: time.Now(),
}
token, err := s.repository.Create(newToken)
return token, err
}
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
}
2023-12-29 00:27:12 +09:00
func (s *tokenService) Invalid(user_id int64, tokenString string) error {
err := s.repository.Invalid(user_id, tokenString)
return err
}
func (s *tokenService) Generate(user_id int64, expire_at int64, role string) (string, error) {
2023-12-27 17:31:49 +09:00
claims := jwt.MapClaims{}
claims["authorized"] = true
claims["sub"] = user_id
claims["exp"] = expire_at
claims["role"] = role
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
}
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 {
return nil, err
}
claims, ok := jwtToken.Claims.(jwt.MapClaims)
if !ok || !jwtToken.Valid {
return nil, errors.New("refresh token is invalid")
}
sub := claims["sub"].(int64)
if err != nil {
return nil, errors.New("wrong user")
}
2023-12-29 00:27:12 +09:00
2023-12-27 17:31:49 +09:00
role := claims["role"].(string)
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(), role)
if err != nil {
return nil, err
}
refreshExpiredAt := time.Now().Add(time.Hour * 24 * 90)
refreshToken, err = s.repository.Generate(sub, refreshExpiredAt.Unix(), role)
if err != nil {
return nil, err
}
token.Token = accessToken
token.EndingAt = expiredAt
token.RefreshToken = refreshToken
return s.repository.Update(token)
}