158 lines
4.3 KiB
Go
158 lines
4.3 KiB
Go
package service
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
"fmt"
|
|
"strings"
|
|
|
|
dto "git.ego.freeddns.org/egommerce/api-entities/identity/dto"
|
|
entity "git.ego.freeddns.org/egommerce/api-entities/identity/entity"
|
|
|
|
"git.ego.freeddns.org/egommerce/identity-service/infra/repository"
|
|
|
|
"github.com/go-redis/redis/v8"
|
|
)
|
|
|
|
var (
|
|
passSrv *PaswordService
|
|
|
|
ErrLoginIncorrect = errors.New("login incorrect")
|
|
ErrUnableToCacheToken = errors.New("unable to save tokens in cache")
|
|
ErrInvalidAccessToken = errors.New("invalid access token")
|
|
ErrParsingAccessToken = errors.New("error while parsing access token")
|
|
ErrUnableToCacheUserID = errors.New("unable to save User ID in cache")
|
|
)
|
|
|
|
func init() {
|
|
passSrv = NewPasswordService()
|
|
}
|
|
|
|
type AuthService struct {
|
|
userRepo *repository.UserRepository
|
|
cache *redis.Client
|
|
}
|
|
|
|
func NewAuthService(userRepo *repository.UserRepository, cache *redis.Client) *AuthService {
|
|
return &AuthService{
|
|
userRepo: userRepo,
|
|
cache: cache,
|
|
}
|
|
}
|
|
|
|
func (a *AuthService) Login(login, passwd string) (string, error) {
|
|
user, err := a.userRepo.FindByUsername(login)
|
|
if err != nil {
|
|
// TODO place code below in better place...
|
|
// if err = database.NoRowsInQuerySet(err); err != nil {
|
|
// return "", errors.New("no user found")
|
|
// }
|
|
|
|
return "", ErrLoginIncorrect
|
|
}
|
|
|
|
if err = passSrv.Verify(passwd, user.Password); err != nil {
|
|
return "", ErrLoginIncorrect
|
|
}
|
|
|
|
accessToken, _ := jwtSrv.CreateAccessToken(user.ID)
|
|
refreshToken, _ := jwtSrv.CreateRefreshToken(user.ID)
|
|
if err = a.saveTokensToCache(user.ID, accessToken, refreshToken); err != nil {
|
|
return "", ErrUnableToCacheToken
|
|
}
|
|
|
|
// REFACTOR: save uid in cache under "user:$ACCES_TOKEN" key
|
|
res := a.cache.Set(context.Background(), "user:"+accessToken, user.ID, accessTokenExpireTime)
|
|
if err := res.Err(); err != nil {
|
|
fmt.Println("failed to save user:$ACCESS_TOKEN in cache: ", err.Error())
|
|
|
|
return "", ErrUnableToCacheUserID
|
|
}
|
|
|
|
return accessToken, nil
|
|
}
|
|
|
|
func (a *AuthService) RefreshToken(accessToken string) (string, error) {
|
|
// POSSIBLE BIG SECURITY ISSUE- WHEN REFRESH WITH ABANDONED (or EXPIRED)
|
|
// ACCESS TOKEN WE GET NEW ACCESS TOKEN
|
|
token, claims, err := jwtSrv.ValidateAccessToken(accessToken)
|
|
if err != nil || !token.Valid {
|
|
return "", ErrInvalidAccessToken
|
|
}
|
|
|
|
userID := claims["sub"]
|
|
|
|
newAccessToken, _ := jwtSrv.CreateAccessToken(userID.(string))
|
|
newRefreshToken, _ := jwtSrv.CreateRefreshToken(userID.(string))
|
|
if err = a.saveTokensToCache(userID.(string), newAccessToken, newRefreshToken); err != nil {
|
|
return "", ErrUnableToCacheToken
|
|
}
|
|
|
|
// REFACTOR
|
|
del := a.cache.Del(context.Background(), "user:"+accessToken)
|
|
if err := del.Err(); err != nil {
|
|
fmt.Println("failed to invalidate user:$ACCESS_TOKEN from cache: ", err.Error())
|
|
}
|
|
|
|
// REFACTOR: save uid in cache under user:$ACCES_TOKEN key
|
|
res := a.cache.Set(context.Background(), "user:"+newAccessToken, userID, accessTokenExpireTime)
|
|
if err := res.Err(); err != nil {
|
|
fmt.Println("failed to save user:$ACCESS_TOKEN in cache: ", err.Error())
|
|
}
|
|
|
|
return newAccessToken, nil
|
|
}
|
|
|
|
func (a *AuthService) Register(email, login, passwd string) (string, error) {
|
|
passwd, _ = passSrv.Hash(passwd)
|
|
|
|
id, err := a.userRepo.Create(&entity.User{
|
|
Email: email,
|
|
Username: login,
|
|
Password: passwd,
|
|
})
|
|
if err != nil {
|
|
return "", err
|
|
}
|
|
|
|
return id, nil
|
|
}
|
|
|
|
func (a *AuthService) GetTokenFromAuthorizationHeader(header *dto.AuthorizationHeaderDTO) (string, error) {
|
|
split := strings.Split(header.Authorization, " ")
|
|
if len(split) != 2 {
|
|
return "", ErrParsingAccessToken
|
|
}
|
|
|
|
return split[1], nil
|
|
}
|
|
|
|
func (a *AuthService) getUIDByAccesssToken(aToken string) (string, error) {
|
|
res := a.cache.Get(context.Background(), "user:"+aToken)
|
|
if err := res.Err(); err != nil {
|
|
return "", err
|
|
}
|
|
|
|
uid, _ := res.Result()
|
|
|
|
return uid, nil
|
|
}
|
|
|
|
func (a *AuthService) saveTokensToCache(id, aToken, rToken string) error {
|
|
res := a.cache.Set(context.Background(), "auth:access_token:"+id, aToken, accessTokenExpireTime)
|
|
if err := res.Err(); err != nil {
|
|
fmt.Println("failed to save access token in cache: ", err.Error())
|
|
|
|
return err
|
|
}
|
|
|
|
res = a.cache.Set(context.Background(), "auth:refresh_token:"+id, rToken, refreshTokenExpireTime)
|
|
if err := res.Err(); err != nil {
|
|
fmt.Println("failed to save refresh token in cache: ", err.Error())
|
|
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|