Refresh Token Support and package refactor based on best practice docs #18
@ -15,6 +15,9 @@ const (
|
||||
)
|
||||
|
||||
type RefreshTokenTable interface {
|
||||
Create(username string, token string, expiresAt time.Time) (int64, error)
|
||||
GetByUsername(name string) (domain.RefreshTokenEntity, error)
|
||||
DeleteById(id int64) (int64, error)
|
||||
}
|
||||
|
||||
type RefreshTokenRepository struct {
|
||||
@ -63,7 +66,7 @@ func (rt RefreshTokenRepository) GetByUsername(name string) (domain.RefreshToken
|
||||
return data[0], nil
|
||||
}
|
||||
|
||||
func (rt RefreshTokenRepository) DeleteById(id int) (int64, error) {
|
||||
func (rt RefreshTokenRepository) DeleteById(id int64) (int64, error) {
|
||||
builder := sqlbuilder.NewDeleteBuilder()
|
||||
builder.DeleteFrom(refreshTokenTableName)
|
||||
builder.Where(
|
||||
@ -71,19 +74,19 @@ func (rt RefreshTokenRepository) DeleteById(id int) (int64, error) {
|
||||
)
|
||||
|
||||
query, args := builder.Build()
|
||||
_, err := rt.connection.Exec(query, args...)
|
||||
rows, err := rt.connection.Exec(query, args...)
|
||||
if err != nil {
|
||||
return -1, err
|
||||
}
|
||||
|
||||
return 1, nil
|
||||
return rows.RowsAffected()
|
||||
}
|
||||
|
||||
func (rd RefreshTokenRepository) processRows(rows *sql.Rows) []domain.RefreshTokenEntity {
|
||||
items := []domain.RefreshTokenEntity{}
|
||||
|
||||
for rows.Next() {
|
||||
var id int
|
||||
var id int64
|
||||
var username string
|
||||
var token string
|
||||
var expiresAt time.Time
|
||||
|
72
internal/services/refreshTokenService.go
Normal file
72
internal/services/refreshTokenService.go
Normal file
@ -0,0 +1,72 @@
|
||||
package services
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"time"
|
||||
|
||||
"git.jamestombleson.com/jtom38/go-cook/internal/domain"
|
||||
"git.jamestombleson.com/jtom38/go-cook/internal/repositories"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type RefreshToken interface {
|
||||
Create(username string, expiresAt time.Time) (string, error)
|
||||
GetByName(name string) (domain.RefreshTokenEntity, error)
|
||||
Delete(id int64) (int64, error)
|
||||
IsRequestValid(username, refreshToken string, jwtExpiresAt time.Time) error
|
||||
}
|
||||
|
||||
type RefreshTokenService struct {
|
||||
table repositories.RefreshTokenTable
|
||||
}
|
||||
|
||||
func NewRefreshTokenService(conn *sql.DB) RefreshTokenService {
|
||||
return RefreshTokenService{
|
||||
table: repositories.NewRefreshTokenRepository(conn),
|
||||
}
|
||||
}
|
||||
|
||||
func (rt RefreshTokenService) Create(username string, expiresAt time.Time) (string, error) {
|
||||
token, err := uuid.NewV7()
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
rows, err := rt.table.Create(username, token.String(), expiresAt)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
if rows != 1 {
|
||||
return "", errors.New("expected one row but got none")
|
||||
}
|
||||
return token.String(), nil
|
||||
}
|
||||
|
||||
// Find the saved refresh token for a user and return it if it exists
|
||||
func (rt RefreshTokenService) GetByName(name string) (domain.RefreshTokenEntity, error) {
|
||||
return rt.table.GetByUsername(name)
|
||||
}
|
||||
|
||||
// This will request that a object is removed from the database
|
||||
func (rt RefreshTokenService) Delete(id int64) (int64, error) {
|
||||
return rt.table.DeleteById(id)
|
||||
}
|
||||
|
||||
func (rt RefreshTokenService) IsRequestValid(username, refreshToken string, jwtExpiresAt time.Time) error {
|
||||
token, err := rt.GetByName(username)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if (token.Token != refreshToken) {
|
||||
return errors.New("the refresh token given does not match")
|
||||
}
|
||||
|
||||
if (token.ExpiresAt != jwtExpiresAt) {
|
||||
return errors.New("the time when the jwt token expires does not match what was given")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
Loading…
Reference in New Issue
Block a user