реструктурирован код
This commit is contained in:
parent
39a79d956b
commit
5da8a4754d
37
main.go
37
main.go
@ -1,7 +1,12 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"backend/src"
|
||||
"backend/src/handlers"
|
||||
"backend/src/middleware"
|
||||
"backend/src/models"
|
||||
"backend/src/repo"
|
||||
"backend/src/services"
|
||||
"backend/src/utils"
|
||||
"crypto/rand"
|
||||
"crypto/rsa"
|
||||
|
||||
@ -30,27 +35,31 @@ func main() {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
jwtUtil := src.NewJwtUtil(key)
|
||||
passwordUtil := src.NewPasswordUtil()
|
||||
db := src.NewDB(sqlDb)
|
||||
userService := src.NewUserService(src.UserServiceDeps{
|
||||
Jwt: jwtUtil,
|
||||
Password: passwordUtil,
|
||||
Db: db,
|
||||
Cache: src.NewCacheInmem[string, src.UserDTO](60 * 60),
|
||||
})
|
||||
jwtUtil := utils.NewJwtUtil(key)
|
||||
passwordUtil := utils.NewPasswordUtil()
|
||||
userRepo := repo.NewUserRepo(sqlDb)
|
||||
userCache := repo.NewCacheInmem[string, models.UserDTO](60 * 60)
|
||||
|
||||
userService := services.NewUserService(
|
||||
services.UserServiceDeps{
|
||||
Jwt: jwtUtil,
|
||||
Password: passwordUtil,
|
||||
UserRepo: userRepo,
|
||||
UserCache: userCache,
|
||||
},
|
||||
)
|
||||
|
||||
r := gin.New()
|
||||
r.Use(gin.Logger())
|
||||
r.Use(gin.Recovery())
|
||||
|
||||
userGroup := r.Group("/user")
|
||||
userGroup.POST("/create", src.NewUserCreateHandler(userService))
|
||||
userGroup.POST("/login", src.NewUserLoginHandler(userService))
|
||||
userGroup.POST("/create", handlers.NewUserCreateHandler(userService))
|
||||
userGroup.POST("/login", handlers.NewUserLoginHandler(userService))
|
||||
|
||||
dummyGroup := r.Group("/dummy")
|
||||
dummyGroup.Use(src.NewAuthMiddleware(userService))
|
||||
dummyGroup.GET("/", src.NewDummyHandler())
|
||||
dummyGroup.Use(middleware.NewAuthMiddleware(userService))
|
||||
dummyGroup.GET("/", handlers.NewDummyHandler())
|
||||
|
||||
r.Run(":8080")
|
||||
}
|
||||
|
||||
70
src/db.go
70
src/db.go
@ -1,70 +0,0 @@
|
||||
package src
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
)
|
||||
|
||||
type DB interface {
|
||||
CreateUser(ctx context.Context, dto UserDTO) (*UserDTO, error)
|
||||
GetUserById(ctx context.Context, id string) (*UserDTO, error)
|
||||
GetUserByLogin(ctx context.Context, login string) (*UserDTO, error)
|
||||
}
|
||||
|
||||
func NewDB(db *sql.DB) DB {
|
||||
return &dbImpl{db}
|
||||
}
|
||||
|
||||
type dbImpl struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func (d *dbImpl) CreateUser(ctx context.Context, dto UserDTO) (*UserDTO, error) {
|
||||
query := `insert into users (login, secret, name) values ($1, $2, $3) returning id;`
|
||||
row := d.db.QueryRowContext(ctx, query, dto.Login, dto.Secret, dto.Name)
|
||||
|
||||
id := ""
|
||||
if err := row.Scan(&id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &UserDTO{
|
||||
Id: id,
|
||||
Login: dto.Login,
|
||||
Secret: dto.Secret,
|
||||
Name: dto.Name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *dbImpl) GetUserById(ctx context.Context, id string) (*UserDTO, error) {
|
||||
query := `select id, login, secret, name from users where id = $1;`
|
||||
row := d.db.QueryRowContext(ctx, query, id)
|
||||
|
||||
dto := &UserDTO{}
|
||||
err := row.Scan(&dto.Id, &dto.Login, &dto.Secret, &dto.Name)
|
||||
if err == nil {
|
||||
return dto, nil
|
||||
}
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (d *dbImpl) GetUserByLogin(ctx context.Context, login string) (*UserDTO, error) {
|
||||
query := `select id, login, secret, name from users where login = $1;`
|
||||
row := d.db.QueryRowContext(ctx, query, login)
|
||||
|
||||
dto := &UserDTO{}
|
||||
err := row.Scan(&dto.Id, &dto.Login, &dto.Secret, &dto.Name)
|
||||
if err == nil {
|
||||
return dto, nil
|
||||
}
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package src
|
||||
package handlers
|
||||
|
||||
import "github.com/gin-gonic/gin"
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
package src
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"backend/src/services"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@ -18,7 +19,7 @@ type createUserOutput struct {
|
||||
Name string `json:"name"`
|
||||
}
|
||||
|
||||
func NewUserCreateHandler(userService UserService) gin.HandlerFunc {
|
||||
func NewUserCreateHandler(userService services.UserService) gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
params := createUserInput{}
|
||||
if err := ctx.ShouldBindJSON(¶ms); err != nil {
|
||||
@ -26,12 +27,12 @@ func NewUserCreateHandler(userService UserService) gin.HandlerFunc {
|
||||
return
|
||||
}
|
||||
|
||||
dto, err := userService.CreateUser(ctx, UserCreateParams{
|
||||
dto, err := userService.CreateUser(ctx, services.UserCreateParams{
|
||||
Login: params.Login,
|
||||
Password: params.Password,
|
||||
Name: params.Name,
|
||||
})
|
||||
if err == ErrUserExists || err == ErrUserBadPassword {
|
||||
if err == services.ErrUserExists || err == services.ErrUserBadPassword {
|
||||
ctx.Data(400, "plain/text", []byte(err.Error()))
|
||||
return
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
package src
|
||||
package handlers
|
||||
|
||||
import (
|
||||
"backend/src/services"
|
||||
"encoding/json"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
@ -15,7 +16,7 @@ type loginUserOutput struct {
|
||||
Token string `json:"token"`
|
||||
}
|
||||
|
||||
func NewUserLoginHandler(userService UserService) gin.HandlerFunc {
|
||||
func NewUserLoginHandler(userService services.UserService) gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
params := loginUserInput{}
|
||||
if err := ctx.ShouldBindJSON(¶ms); err != nil {
|
||||
@ -24,7 +25,7 @@ func NewUserLoginHandler(userService UserService) gin.HandlerFunc {
|
||||
}
|
||||
|
||||
token, err := userService.AuthenticateUser(ctx, params.Login, params.Password)
|
||||
if err == ErrUserNotExists || err == ErrUserWrongPassword {
|
||||
if err == services.ErrUserNotExists || err == services.ErrUserWrongPassword {
|
||||
ctx.AbortWithError(400, err)
|
||||
return
|
||||
}
|
||||
@ -1,12 +1,13 @@
|
||||
package src
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"backend/src/services"
|
||||
"fmt"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
func NewAuthMiddleware(userService UserService) gin.HandlerFunc {
|
||||
func NewAuthMiddleware(userService services.UserService) gin.HandlerFunc {
|
||||
return func(ctx *gin.Context) {
|
||||
token := ctx.GetHeader("X-Auth")
|
||||
if token == "" {
|
||||
@ -15,7 +16,7 @@ func NewAuthMiddleware(userService UserService) gin.HandlerFunc {
|
||||
}
|
||||
|
||||
user, err := userService.ValidateToken(ctx, token)
|
||||
if err == ErrUserWrongToken || err == ErrUserNotExists {
|
||||
if err == services.ErrUserWrongToken || err == services.ErrUserNotExists {
|
||||
ctx.AbortWithError(403, err)
|
||||
return
|
||||
}
|
||||
15
src/model.go
15
src/model.go
@ -1,15 +0,0 @@
|
||||
package src
|
||||
|
||||
type UserDTO struct {
|
||||
Id string
|
||||
Login string
|
||||
Secret string
|
||||
Name string
|
||||
}
|
||||
|
||||
type UserDAO struct {
|
||||
Id string `json:"id"`
|
||||
Login string `json:"login"`
|
||||
Secret string `json:"secret"`
|
||||
Name string `json:"name"`
|
||||
}
|
||||
8
src/models/user.go
Normal file
8
src/models/user.go
Normal file
@ -0,0 +1,8 @@
|
||||
package models
|
||||
|
||||
type UserDTO struct {
|
||||
Id string
|
||||
Login string
|
||||
Secret string
|
||||
Name string
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
package src
|
||||
package repo
|
||||
|
||||
import (
|
||||
"sync"
|
||||
78
src/repo/user_repo.go
Normal file
78
src/repo/user_repo.go
Normal file
@ -0,0 +1,78 @@
|
||||
package repo
|
||||
|
||||
import (
|
||||
"backend/src/models"
|
||||
"context"
|
||||
"database/sql"
|
||||
"errors"
|
||||
)
|
||||
|
||||
// type userDAO struct {
|
||||
// Id string `json:"id"`
|
||||
// Login string `json:"login"`
|
||||
// Secret string `json:"secret"`
|
||||
// Name string `json:"name"`
|
||||
// }
|
||||
|
||||
type UserRepo interface {
|
||||
CreateUser(ctx context.Context, dto models.UserDTO) (*models.UserDTO, error)
|
||||
GetUserById(ctx context.Context, id string) (*models.UserDTO, error)
|
||||
GetUserByLogin(ctx context.Context, login string) (*models.UserDTO, error)
|
||||
}
|
||||
|
||||
func NewUserRepo(db *sql.DB) UserRepo {
|
||||
return &userRepo{db}
|
||||
}
|
||||
|
||||
type userRepo struct {
|
||||
db *sql.DB
|
||||
}
|
||||
|
||||
func (u *userRepo) CreateUser(ctx context.Context, dto models.UserDTO) (*models.UserDTO, error) {
|
||||
query := `insert into users (login, secret, name) values ($1, $2, $3) returning id;`
|
||||
row := u.db.QueryRowContext(ctx, query, dto.Login, dto.Secret, dto.Name)
|
||||
|
||||
id := ""
|
||||
if err := row.Scan(&id); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &models.UserDTO{
|
||||
Id: id,
|
||||
Login: dto.Login,
|
||||
Secret: dto.Secret,
|
||||
Name: dto.Name,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (u *userRepo) GetUserById(ctx context.Context, id string) (*models.UserDTO, error) {
|
||||
query := `select id, login, secret, name from users where id = $1;`
|
||||
row := u.db.QueryRowContext(ctx, query, id)
|
||||
|
||||
dto := &models.UserDTO{}
|
||||
err := row.Scan(&dto.Id, &dto.Login, &dto.Secret, &dto.Name)
|
||||
if err == nil {
|
||||
return dto, nil
|
||||
}
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
|
||||
func (u *userRepo) GetUserByLogin(ctx context.Context, login string) (*models.UserDTO, error) {
|
||||
query := `select id, login, secret, name from users where login = $1;`
|
||||
row := u.db.QueryRowContext(ctx, query, login)
|
||||
|
||||
dto := &models.UserDTO{}
|
||||
err := row.Scan(&dto.Id, &dto.Login, &dto.Secret, &dto.Name)
|
||||
if err == nil {
|
||||
return dto, nil
|
||||
}
|
||||
if errors.Is(err, sql.ErrNoRows) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
return nil, err
|
||||
}
|
||||
@ -1,6 +1,9 @@
|
||||
package src
|
||||
package services
|
||||
|
||||
import (
|
||||
"backend/src/models"
|
||||
"backend/src/repo"
|
||||
"backend/src/utils"
|
||||
"context"
|
||||
"fmt"
|
||||
)
|
||||
@ -15,9 +18,9 @@ var (
|
||||
)
|
||||
|
||||
type UserService interface {
|
||||
CreateUser(ctx context.Context, params UserCreateParams) (*UserDTO, error)
|
||||
CreateUser(ctx context.Context, params UserCreateParams) (*models.UserDTO, error)
|
||||
AuthenticateUser(ctx context.Context, login, password string) (string, error)
|
||||
ValidateToken(ctx context.Context, tokenStr string) (*UserDTO, error)
|
||||
ValidateToken(ctx context.Context, tokenStr string) (*models.UserDTO, error)
|
||||
}
|
||||
|
||||
func NewUserService(deps UserServiceDeps) UserService {
|
||||
@ -25,10 +28,10 @@ func NewUserService(deps UserServiceDeps) UserService {
|
||||
}
|
||||
|
||||
type UserServiceDeps struct {
|
||||
Db DB
|
||||
Jwt JwtUtil
|
||||
Password PasswordUtil
|
||||
Cache Cache[string, UserDTO]
|
||||
Jwt utils.JwtUtil
|
||||
Password utils.PasswordUtil
|
||||
UserRepo repo.UserRepo
|
||||
UserCache repo.Cache[string, models.UserDTO]
|
||||
}
|
||||
|
||||
type userService struct {
|
||||
@ -41,8 +44,8 @@ type UserCreateParams struct {
|
||||
Name string
|
||||
}
|
||||
|
||||
func (u *userService) CreateUser(ctx context.Context, params UserCreateParams) (*UserDTO, error) {
|
||||
exisitngUser, err := u.deps.Db.GetUserByLogin(ctx, params.Login)
|
||||
func (u *userService) CreateUser(ctx context.Context, params UserCreateParams) (*models.UserDTO, error) {
|
||||
exisitngUser, err := u.deps.UserRepo.GetUserByLogin(ctx, params.Login)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -59,24 +62,24 @@ func (u *userService) CreateUser(ctx context.Context, params UserCreateParams) (
|
||||
return nil, err
|
||||
}
|
||||
|
||||
user := UserDTO{
|
||||
user := models.UserDTO{
|
||||
Login: params.Login,
|
||||
Secret: string(secret),
|
||||
Name: params.Name,
|
||||
}
|
||||
|
||||
result, err := u.deps.Db.CreateUser(ctx, user)
|
||||
result, err := u.deps.UserRepo.CreateUser(ctx, user)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
u.deps.Cache.Set(result.Id, *result, -1)
|
||||
u.deps.UserCache.Set(result.Id, *result, -1)
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
func (u *userService) AuthenticateUser(ctx context.Context, login, password string) (string, error) {
|
||||
user, err := u.deps.Db.GetUserByLogin(ctx, login)
|
||||
user, err := u.deps.UserRepo.GetUserByLogin(ctx, login)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
@ -88,22 +91,23 @@ func (u *userService) AuthenticateUser(ctx context.Context, login, password stri
|
||||
return "", ErrUserWrongPassword
|
||||
}
|
||||
|
||||
jwt, err := u.deps.Jwt.Create(*user)
|
||||
payload := utils.JwtPayload{UserId: user.Id}
|
||||
jwt, err := u.deps.Jwt.Create(payload)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
u.deps.Cache.Set(user.Id, *user, -1)
|
||||
u.deps.UserCache.Set(user.Id, *user, -1)
|
||||
|
||||
return jwt, nil
|
||||
}
|
||||
|
||||
func (u *userService) getUserById(ctx context.Context, userId string) (*UserDTO, error) {
|
||||
if user, ok := u.deps.Cache.Get(userId); ok {
|
||||
func (u *userService) getUserById(ctx context.Context, userId string) (*models.UserDTO, error) {
|
||||
if user, ok := u.deps.UserCache.Get(userId); ok {
|
||||
return &user, nil
|
||||
}
|
||||
|
||||
user, err := u.deps.Db.GetUserById(ctx, userId)
|
||||
user, err := u.deps.UserRepo.GetUserById(ctx, userId)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@ -111,12 +115,12 @@ func (u *userService) getUserById(ctx context.Context, userId string) (*UserDTO,
|
||||
return nil, ErrUserNotExists
|
||||
}
|
||||
|
||||
u.deps.Cache.Set(user.Id, *user, -1)
|
||||
u.deps.UserCache.Set(user.Id, *user, -1)
|
||||
|
||||
return user, nil
|
||||
}
|
||||
|
||||
func (u *userService) ValidateToken(ctx context.Context, tokenStr string) (*UserDTO, error) {
|
||||
func (u *userService) ValidateToken(ctx context.Context, tokenStr string) (*models.UserDTO, error) {
|
||||
payload, err := u.deps.Jwt.Parse(tokenStr)
|
||||
if err != nil {
|
||||
return nil, ErrUserWrongToken
|
||||
@ -1,4 +1,4 @@
|
||||
package src
|
||||
package utils
|
||||
|
||||
import (
|
||||
"crypto/rsa"
|
||||
@ -8,12 +8,16 @@ import (
|
||||
)
|
||||
|
||||
type JwtPayload struct {
|
||||
jwt.RegisteredClaims
|
||||
UserId string `json:"userId"`
|
||||
}
|
||||
|
||||
type jwtClaims struct {
|
||||
jwt.RegisteredClaims
|
||||
JwtPayload
|
||||
}
|
||||
|
||||
type JwtUtil interface {
|
||||
Create(user UserDTO) (string, error)
|
||||
Create(payload JwtPayload) (string, error)
|
||||
Parse(tokenStr string) (JwtPayload, error)
|
||||
}
|
||||
|
||||
@ -27,9 +31,9 @@ type jwtUtil struct {
|
||||
privateKey *rsa.PrivateKey
|
||||
}
|
||||
|
||||
func (j *jwtUtil) Create(user UserDTO) (string, error) {
|
||||
payload := &JwtPayload{UserId: user.Id}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodRS256, payload)
|
||||
func (j *jwtUtil) Create(payload JwtPayload) (string, error) {
|
||||
claims := &jwtClaims{JwtPayload: payload}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
|
||||
tokenStr, err := token.SignedString(j.privateKey)
|
||||
if err != nil {
|
||||
return "", err
|
||||
@ -38,15 +42,15 @@ func (j *jwtUtil) Create(user UserDTO) (string, error) {
|
||||
}
|
||||
|
||||
func (j *jwtUtil) Parse(tokenStr string) (JwtPayload, error) {
|
||||
token, err := jwt.ParseWithClaims(tokenStr, &JwtPayload{}, func(t *jwt.Token) (interface{}, error) {
|
||||
token, err := jwt.ParseWithClaims(tokenStr, &jwtClaims{}, func(t *jwt.Token) (interface{}, error) {
|
||||
return &j.privateKey.PublicKey, nil
|
||||
})
|
||||
if err != nil {
|
||||
return JwtPayload{}, err
|
||||
}
|
||||
|
||||
if payload, ok := token.Claims.(*JwtPayload); ok {
|
||||
return *payload, nil
|
||||
if claims, ok := token.Claims.(*jwtClaims); ok {
|
||||
return claims.JwtPayload, nil
|
||||
}
|
||||
|
||||
return JwtPayload{}, fmt.Errorf("cant get payload")
|
||||
@ -1,4 +1,4 @@
|
||||
package src
|
||||
package utils
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
Loading…
x
Reference in New Issue
Block a user